版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35649707/article/details/82716869
题解:
相当于把观察排序,然后求一个最小链覆盖。
根据某D开头的定理,相当于是求最长反链。
考虑树形DP,一个方案在
的子树中为反链当且仅当:
1.在
的所有邻接点的子树中为反链。
2.存在一个时间
不能到达方案中的任意一个点。
因为每个点不能到达的时间是一个区间,我们可以维护 表示 的子树中公共时间为 的最优方案。因为重复的很多,我们可以只维护差分数组,当然可能不存在整数解,我们先把所有区间乘2保证有整数解。
每次往上转移长度 只需要向左右取个max即可。 相当于差分数组中正的往左移,负的往右移动。 两个差分点遇到则保留较大的那个,然后删除较小的,较大的值改为他们的和。 因为每次删除会丢掉一个点,这里是 的。
只用考虑如果加入当前点 。 首先不加入就相当于直接左右取max,加入则只能加到 处,而且影响的区间只有 ,这个处理的时候要注意一下。可以直接考虑连成两条边分别是 分开考虑。
合并两个差分数组直接加入即可。 若用启发式合并,复杂度为 。
#include <bits/stdc++.h>
using namespace std;
#define pii pair <int,int>
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
const int N=1e5+50;
const int INF=0x3f3f3f3f;
int n,q; int det[N];
vector <pii> edge[N];
vector <pii> ask[N];
struct Myset {
int id;
struct data {
int first,second; int id;
data(int first,int second,int id) : first(first), second(second), id(id) {}
friend inline bool operator <(const data &a,const data &b) {
int posa=a.first+((a.second>0) ? -det[a.id] : det[a.id]),
posb=b.first+((b.second>0) ? -det[b.id] : det[b.id]);
if(posa!=posb) return posa<posb;
return a.second<b.second;
}
};
typedef set <data> Set;
typedef Set :: iterator it;
inline it prev(it t) {return --t;}
inline it suff(it t) {return ++t;}
Set *s;
set <pii> *dis;
inline int sgn(int x) {return (x>0) ? 1 : 0;}
Myset() {s=new Set; dis=new set <pii>;}
inline int getpos(it t) {return t->first+((t->second<0) ? det[t->id] : -det[t->id]);}
inline void del_dis(it x,it y) {
if(sgn(x->second) || !sgn(y->second)) return;
dis->erase(dis->find(pii(y->first-x->first,y->first)));
}
inline void inc_dis(it x,it y) {
if(sgn(x->second) || !sgn(y->second)) return;
dis->insert(pii(y->first-x->first,y->first));
}
inline void _erase(it x) {
if(x!=s->begin()) del_dis(prev(x),x);
if(x!=--s->end()) del_dis(x,suff(x));
if(x!=s->begin() && x!=--s->end()) inc_dis(prev(x),suff(x));
s->erase(x);
}
inline void add(int pos,int d) {
if(!d) return;
it nxt=s->lower_bound(data(pos-det[id],-INF,id));
if(nxt==s->end() || getpos(nxt) !=pos) {
if(s->size()>=2 && getpos(s->begin())<pos && getpos(--s->end())>pos) del_dis(prev(nxt),nxt);
data temp=data(pos+((d<0)?-det[id]:det[id]),d,id);
it now=s->insert(temp).first;
if(nxt!=s->end()) inc_dis(now,nxt);
if(now!=s->begin()) inc_dis(prev(now),now);
} else {
data temp=*nxt; _erase(nxt);
if(!(temp.second+d)) return;
if(temp.second<0 && temp.second+d>0) temp.first+=2*det[id];
if(temp.second>0 && temp.second+d<0) temp.first-=2*det[id];
temp.second+=d;
it nxt=s->insert(temp).first;
if(nxt!=--s->end()) inc_dis(nxt,suff(nxt));
if(nxt!=s->begin()) inc_dis(prev(nxt),nxt);
if(nxt!=--s->end() && nxt!=s->begin()) del_dis(prev(nxt),suff(nxt));
}
}
inline void md(int pos,int d) {add(pos,d); add(pos+1,-d);}
inline void mv(int d) {
if(!d) return;
while(dis->size() && dis->begin()->first<=(d+det[id])*2) {
it nxt=s->lower_bound(data(dis->begin()->second-2*det[id],-INF,id));
if(nxt->second==-prev(nxt)->second) _erase(prev(nxt)), _erase(nxt);
else if(nxt->second>-prev(nxt)->second) {
int val=prev(nxt)->second;
_erase(prev(nxt));
add(nxt->first-det[id],val);
} else {
int val=nxt->second; nxt=prev(nxt);
_erase(suff(nxt));
add(nxt->first+det[id],val);
}
} det[id]+=d;
}
inline void merge(Myset &b) {
if(s->size()<b.s->size()) swap(s,b.s), swap(id,b.id), swap(dis,b.dis);
for(it v=b.s->begin();v!=b.s->end();++v) {
data temp=*v; temp.first+=(v->second<0) ? det[b.id] : -det[b.id];
add(temp.first,temp.second);
} delete b.s; delete b.dis;
}
inline int getval(int pos) {
it nxt=s->lower_bound(data(pos-det[id],-INF,id));
if(nxt!=s->end() && getpos(nxt)==pos) return nxt->second;
return 0;
}
} s[N];
inline void dfs(int x,int f) {
for(auto v:edge[x]) {
if(v.first==f) continue;
dfs(v.first,x);
for(auto &d:ask[v.first]) {
int delta=max(0,max(-s[v.first].getval(d.first),s[v.first].getval(d.first+1)));
d.second=max(0,d.second-delta);
}
s[v.first].mv(1);
for(auto d:ask[v.first]) s[v.first].md(d.first,d.second);
s[v.first].mv(v.second-1);
s[x].merge(s[v.first]);
}
}
int main() {
n=rd();
for(int i=1;i<=n;i++) s[i].id=i;
for(int i=1;i<n;i++) {
int x=rd(), y=rd(), w=rd()*2;
edge[x].push_back(pii(y,w));
edge[y].push_back(pii(x,w));
} edge[0].push_back(pii(1,2));
q=rd();
for(int i=1;i<=q;i++) {
int d=2*rd(), f=rd(), p=rd();
ask[p].push_back(pii(d,f));
} dfs(0,0);
if(!s[0].s) {puts("0"); return 0;}
int sum=0, mx=0;
for(auto v=s[0].s->begin();v!=s[0].s->end();++v) {
sum+=v->second;
mx=max(mx,sum);
} cout<<mx<<'\n';
}