题目
首先这个题看起来这个最小值不好在动态点分治时维护。
(居然)可以转化。
最小值于树的带权重心处取到。
带权带的是点权。
树的带权重心是
子
树
权
∗
2
>
=
总
树
权
子树权*2>=总树权
子树权∗2>=总树权的点中最深的。
不可能会有多个因为
子
树
权
∗
2
>
=
总
树
权
子树权*2>=总树权
子树权∗2>=总树权的点一定形成一条由根出发的链。
那么就可以动态修改子树权,在树链上二分了。
等等,我们都不知道是哪条树链,怎么二分?
因为树链上的点的dfs序递增。
可是万一二分的时候取到了链外的点呢,单调性何在?
求个前缀最大值就有单调性了。。。。。。
可是前缀最大值维护还需要一个
log
\log
log,你慢死了。
线段树二分啊。。。。。。
最后知道最值点,直接用动态点分治求答案就行了。
因为点的度数<=20,直接用边分治了。
注意边分树深度可能大于
log
n
\log n
logn
AC Code:
#include<bits/stdc++.h>
#define maxn 100005
#define lim 30
#define lc now << 1
#define rc now << 1 | 1
#define LL long long
using namespace std;
int n,q;
LL cst[maxn<<1];
int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e=1;
void Node(int u,int v,int c){Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cst[cnt_e]=c;}
bool vis[maxn<<1];
int siz[maxn],id[maxn],pos[maxn],son[maxn],tp[maxn],fa[maxn],tot;
int rt,Min;
void dfs(int now,int ff,int tsz){
siz[now] = 1;
for(int i=info[now];i;i=Prev[i])
if(to[i]!=ff && !vis[i]){
dfs(to[i],now,tsz);
siz[now] += siz[to[i]];
if(Min > max(siz[to[i]],tsz-siz[to[i]]))
Min = max(siz[to[i]],tsz-siz[to[i]]),
rt = i;
}
}
int findrt(int now,int tsz){
Min = 0x3f3f3f3f , rt = -1;
dfs(now,0,tsz);
return rt;
}
int sid[maxn][lim] , f[maxn][lim] , Dep[maxn];
LL s1[maxn<<1][2],s2[maxn<<1][2], fdis[maxn][lim];
void ser(int now,int ff,int dist,int dep,int pfa,int side){
f[now][dep] = pfa , fdis[now][dep] = dist , sid[now][dep] = side;
siz[now] = 1;
for(int i=info[now];i;i=Prev[i])
if(to[i]!=ff && !vis[i]){
ser(to[i],now,dist+cst[i],dep,pfa,side);
siz[now] += siz[to[i]];
}
}
void Solve(int now,int dep){
vis[now] = vis[now^1] = 1;
ser(to[now],0,0,dep,now,0);
ser(to[now^1],0,0,dep,now,1);
int rt1 = findrt(to[now],siz[to[now]]);
if(rt1 == -1) Dep[to[now]] = dep;
else Solve(rt1,dep+1);
rt1 = findrt(to[now^1],siz[to[now^1]]);
if(rt1 == -1) Dep[to[now^1]] = dep;
else Solve(rt1,dep+1);
}
void modifytree(int now,int v){
for(int i=Dep[now];i>=0;i--)
s1[f[now][i]][sid[now][i]]+=v , s2[f[now][i]][sid[now][i]]+=v*fdis[now][i];
}
LL query(int now){
LL ret = 0;
for(int i=Dep[now];i>=0;i--)
ret += s1[f[now][i]][sid[now][i]^1] * (fdis[now][i] + cst[f[now][i]])
+ s2[f[now][i]][sid[now][i]^1];
return ret;
}
LL add[maxn<<3],Max[maxn<<3];
void dt(int now){
if(add[now]){
Max[now] = Max[now] + add[now];
add[lc] += add[now] , add[rc] += add[now];
add[now] = 0;
}
}
void upd(int now){
Max[now] = max(Max[lc] , Max[rc]);
}
void Insert(int now,int l,int r,int ql,int qr,int v){
dt(now);
if(l>qr || ql>r) return;
if(ql<=l && r<=qr){ add[now]+=v,dt(now);return;}
int mid = (l+r) >> 1;
Insert(lc,l,mid,ql,qr,v),Insert(rc,mid+1,r,ql,qr,v);
upd(now);
}
void modifypath(int now,int v){
for(;now;now=fa[tp[now]])
Insert(1,1,n,id[tp[now]],id[now],v);
}
void dfs1(int now,int ff){
siz[now] = 1 , son[now] = -1;
fa[now] = ff;
for(int i=info[now];i;i=Prev[i])
if(to[i]!=ff){
dfs1(to[i],now);
siz[now] += siz[to[i]];
if(son[now] == -1 || siz[to[i]] > siz[son[now]])
son[now] = to[i];
}
}
void dfs2(int now,int ff){
pos[id[now] = ++tot] = now;
if(son[now]!=-1) tp[son[now]]=tp[now],dfs2(son[now],now);
for(int i=info[now];i;i=Prev[i])
if(to[i]!=ff && to[i]!=son[now])
tp[to[i]] = to[i] , dfs2(to[i],now);
}
int getrt(){
int now = 1,l=1,r=n,mid;
for(;l<r;){
mid = (l+r) >> 1;
dt(now),dt(lc),dt(rc);
if(Max[rc]*2 >= Max[1]) now = rc , l = mid + 1;
else now = lc , r = mid;
}
return pos[l];
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<n;i++){
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
Node(u,v,c),Node(v,u,c);
}
dfs1(1,0),tp[1]=1,dfs2(1,0);
Solve(findrt(1,n),0);
for(int u,e;q--;){
scanf("%d%d",&u,&e);
modifytree(u,e);
modifypath(u,e);
printf("%lld\n",query(getrt()));
}
}