题目分析:
不难发现可以用动态DP做。
题目相当于是要我求一条路径,所有与路径有交的链的代价加入进去,要求代价最大。
我们把链的代价分成两个部分:一部分将代价加入$LCA$之中,用$g$数组保存;另一部分将代价加在整条链上,用$d$数组保存。
这时候我们可以发现,一条从$u$到$v$的路径的代价相当于是$d[LCA(u,v)]+\sum_{x \in edge(u,v)}g[x]$。
如果是静态的,可以用树形DP解决。
看过《神奇的子图》的同学都知道,叶子结点是从它的儿子中取两个最大的出来,所以堆维护。
考虑合并。
链从左延申出的最大的$g$的总和记录。链从右延申包括$d$的总和记录,每次向上$update$的时候拼起来与原答案比较即可。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 6 const int maxn = 102000; 7 8 int n,m; 9 10 vector <int> g[maxn]; 11 int sz[maxn],top[maxn],fa[maxn],dep[maxn],son[maxn],ind[maxn],dr[maxn]; 12 int tail[maxn],num; 13 14 struct Query{int from,to,w;}Q[maxn]; 15 struct Priority_Queue{ 16 priority_queue<ll,vector<ll>,less<ll> > pq,del; 17 void push(ll now){pq.push(now);} 18 void pop(){ 19 while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop(); 20 pq.pop(); 21 } 22 ll top(){ 23 while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop(); 24 if(pq.empty()) return 0; 25 else return pq.top(); 26 } 27 ll sec(){ 28 while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop(); 29 if(pq.size() ==0) return 0; 30 ll oop = pq.top(); pq.pop(); 31 while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop(); 32 if(pq.size() == 0){pq.push(oop);return 0;} 33 else {ll ret = pq.top();pq.push(oop);return ret;} 34 } 35 void Erase(ll now){del.push(now);} 36 }Son[maxn],Ans; 37 38 struct segmentTree{ 39 ll tg,ff,lazy,REC,L,R; 40 }T[maxn<<2]; 41 42 void push_down(int now){ 43 T[now<<1].ff += T[now].lazy; T[now<<1|1].ff += T[now].lazy; 44 T[now<<1].REC += T[now].lazy; T[now<<1|1].REC += T[now].lazy; 45 T[now<<1].lazy += T[now].lazy; T[now<<1|1].lazy += T[now].lazy; 46 T[now<<1].R += T[now].lazy; T[now<<1|1].R += T[now].lazy; 47 T[now].lazy = 0; 48 } 49 50 segmentTree merge(segmentTree alpha,segmentTree beta){ 51 segmentTree RES;RES.lazy = 0; RES.ff = 0; 52 RES.tg = alpha.tg + beta.tg; 53 RES.REC = max(alpha.REC,beta.REC); 54 RES.REC = max(RES.REC,alpha.R + beta.L); 55 RES.L = max(alpha.L,alpha.tg + beta.L); 56 RES.R = max(beta.R,alpha.R + beta.tg); 57 return RES; 58 } 59 60 void dfs1(int now,int f,int dp){ 61 dep[now] = dp; fa[now] = f; 62 int maxx = 0; 63 for(auto it:g[now]){ 64 if(it == f) continue; 65 dfs1(it,now,dp+1); 66 sz[now] += sz[it]; 67 if(maxx == 0 || sz[it] > sz[maxx]) maxx = it; 68 } 69 son[now] = maxx; sz[now]++; 70 } 71 72 void dfs2(int now,int tp){ 73 top[now] = tp; ind[now] = ++num; dr[num] = now; 74 if(now == tp) Ans.push(0); 75 if(son[now]) dfs2(son[now],tp); 76 else tail[tp] = now; 77 for(auto it : g[now]){ 78 if(it == fa[now] || it == son[now]) continue; 79 dfs2(it,it); 80 } 81 } 82 83 void read(){ 84 scanf("%d%d",&n,&m); 85 for(int i=1;i<n;i++){ 86 int u,v; scanf("%d%d",&u,&v); 87 g[u].push_back(v); g[v].push_back(u); 88 } 89 } 90 91 int QueryLca(int u,int v){ 92 while(top[u] != top[v]){ 93 if(dep[top[u]] > dep[top[v]]) u = fa[top[u]]; 94 else v = fa[top[v]]; 95 } 96 if(dep[u] < dep[v]) return u; else return v; 97 } 98 99 segmentTree Querylen(int now,int tl,int tr,int l,int r){ 100 if(tl >= l && tr <= r) return T[now]; 101 if(T[now].lazy) push_down(now); 102 int mid = (tl+tr)/2; 103 if(mid < l) return Querylen(now<<1|1,mid+1,tr,l,r); 104 if(mid >= r) return Querylen(now<<1,tl,mid,l,r); 105 segmentTree pp = Querylen(now<<1|1,mid+1,tr,l,r); 106 segmentTree qq = Querylen(now<<1,tl,mid,l,r); 107 return merge(qq,pp); 108 } 109 110 void AddG(int now,int tl,int tr,int place,int w){ 111 if(tl == tr){T[now].tg += w;T[now].L += w;return;} 112 if(T[now].lazy) push_down(now); 113 int mid = (tl+tr)/2; 114 if(mid >= place) AddG(now<<1,tl,mid,place,w); 115 else AddG(now<<1|1,mid+1,tr,place,w); 116 T[now] = merge(T[now<<1],T[now<<1|1]); 117 } 118 119 void ModifyG(int now,int tl,int tr,int place){ 120 if(tl == tr){ 121 tl = dr[tl]; T[now].L = Son[tl].top() + T[now].tg; 122 T[now].REC = T[now].ff + Son[tl].top() + Son[tl].sec(); 123 T[now].R = T[now].ff + Son[tl].top(); 124 return; 125 } 126 if(T[now].lazy) push_down(now); 127 int mid = (tl+tr)/2; 128 if(mid >= place) ModifyG(now<<1,tl,mid,place); 129 else ModifyG(now<<1|1,mid+1,tr,place); 130 T[now] = merge(T[now<<1],T[now<<1|1]); 131 } 132 133 void ModifyF(int now,int tl,int tr,int l,int r,int w){ 134 if(tl >= l && tr <= r){ 135 T[now].lazy += w; T[now].ff += w; T[now].R += w; T[now].REC+=w; 136 return; 137 } 138 if(T[now].lazy) push_down(now); 139 int mid = (tl+tr)/2; 140 if(mid >= l) ModifyF(now<<1,tl,mid,l,r,w); 141 if(mid+1 <= r) ModifyF(now<<1|1,mid+1,tr,l,r,w); 142 T[now] = merge(T[now<<1],T[now<<1|1]); 143 } 144 145 void SingleModify(int now,int w){ 146 int hole = tail[top[now]]; 147 segmentTree fk = Querylen(1,1,n,ind[top[hole]],ind[hole]); 148 AddG(1,1,n,ind[now],w); now=fa[top[now]]; 149 while(now){ 150 segmentTree rl = Querylen(1,1,n,ind[top[hole]],ind[hole]); 151 Ans.Erase(fk.REC); Ans.push(rl.REC); 152 Son[now].Erase(fk.L); Son[now].push(rl.L); 153 hole = tail[top[now]]; fk = Querylen(1,1,n,ind[top[hole]],ind[hole]); 154 ModifyG(1,1,n,ind[now]); now = fa[top[now]]; 155 } 156 Ans.Erase(fk.REC); 157 fk = Querylen(1,1,n,ind[top[hole]],ind[hole]); 158 Ans.push(fk.REC); 159 } 160 161 void WideModify(int now,int LCA,int w){ 162 while(dep[now] >= dep[LCA]){ 163 segmentTree fk = Querylen(1,1,n,ind[top[now]],ind[tail[top[now]]]); 164 if(dep[top[now]] < dep[LCA]) ModifyF(1,1,n,ind[LCA],ind[now],w); 165 else ModifyF(1,1,n,ind[top[now]],ind[now],w); 166 Ans.Erase(fk.REC); 167 fk = Querylen(1,1,n,ind[top[now]],ind[tail[top[now]]]); 168 Ans.push(fk.REC); 169 now = fa[top[now]]; 170 } 171 } 172 173 void Modify(int u,int v,int w){ 174 int LCA = QueryLca(u,v); 175 SingleModify(LCA,w); 176 WideModify(u,LCA,w); // u 177 WideModify(v,LCA,w); // v 178 WideModify(LCA,LCA,-w); // LCA 179 } 180 181 void build_tree(int now,int tl,int tr){ 182 if(tl == tr){ 183 tl = dr[tl]; 184 for(auto it : g[tl]){ 185 if(it == son[tl] || it == fa[tl]) continue; 186 Son[tl].push(0); 187 } 188 }else{ 189 int mid = (tl+tr)/2; 190 build_tree(now<<1,tl,mid); build_tree(now<<1|1,mid+1,tr); 191 } 192 } 193 194 void work(){ 195 dfs1(1,0,1); 196 dfs2(1,1); 197 build_tree(1,1,n); 198 for(int i=1;i<=m;i++){ 199 char ch = getchar(); while(ch != '+' && ch != '-') ch = getchar(); 200 int fr,t,w; 201 if(ch == '+'){ 202 scanf("%d%d%d",&fr,&t,&w);Q[i].from=fr;Q[i].to=t;Q[i].w=w; 203 }else{ 204 int x; scanf("%d",&x);fr = Q[x].from,t = Q[x].to,w = -Q[x].w; 205 } 206 Modify(fr,t,w); 207 printf("%lld\n",Ans.top()); 208 } 209 } 210 211 int main(){ 212 read(); 213 work(); 214 return 0; 215 }