[loj2135]幻想乡战略游戏
以1为根建树,令$D_{i}$为$i$子树内所有节点$d_{i}$之和
令$ans_{i}$为节点$i$的答案,令$fa$为$i$的父亲,则$ans_{i}=ans_{fa}+dis(i,fa)(D_{1}-2D_{i})$
节点$i\ne 1$是最大值的必要条件是其$2D_{i}>D_{1}$,否则一定有$ans_{i}\ge ans_{fa}$
换言之,我们只需要考虑$i=1$或$2D_{i}>D_{1}$的节点,根据$d_{i}$非负的性质,不难证明这是一条以1为端点的链
对于这条链上的节点$i\ne 1$,必然有$ans_{i}<ans_{fa}$,因此最终即求这条链最底部的节点
对其求dfs序,这个最底部的节点也是dfs序最大的节点,线段树维护$D_{i}$最大值二分即可
由于修改是链修改,需要使用树链剖分,复杂度为$o(n\log^{2}n)$,可以通过
另外还需要查询$x$答案,即$ans_{1}+\sum_{i为x祖先或i=x,i\ne 1}dis(i,fa)(D_{1}-2D_{i})$,同样用树链剖分维护即可
(关于其点分的做法复杂度并不正确,因为还需要枚举每一个点的度数来找到移动的节点)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define ll long long 5 #define L (k<<1) 6 #define R (L+1) 7 #define mid (l+r>>1) 8 struct Edge{ 9 int nex,to,len; 10 }edge[N<<1]; 11 int E,n,m,x,y,z,D,head[N],fa[N],sz[N],dep[N],mx[N],dfn[N],idfn[N],top[N],tag[N<<2],f[N<<2]; 12 ll ans,val[N<<2],sum[N<<2]; 13 void add(int x,int y,int z){ 14 edge[E].nex=head[x]; 15 edge[E].to=y; 16 edge[E].len=z; 17 head[x]=E++; 18 } 19 void dfs1(int k,int f,int sh){ 20 fa[k]=f; 21 sz[k]=1; 22 dep[k]=sh; 23 for(int i=head[k];i!=-1;i=edge[i].nex) 24 if (edge[i].to!=f){ 25 dfs1(edge[i].to,k,sh+edge[i].len); 26 sz[k]+=sz[edge[i].to]; 27 if (sz[mx[k]]<sz[edge[i].to])mx[k]=edge[i].to; 28 } 29 } 30 void dfs2(int k,int fa,int t){ 31 dfn[k]=++dfn[0]; 32 idfn[dfn[0]]=k; 33 top[k]=t; 34 if (mx[k])dfs2(mx[k],k,t); 35 for(int i=head[k];i!=-1;i=edge[i].nex) 36 if ((edge[i].to!=fa)&&(edge[i].to!=mx[k]))dfs2(edge[i].to,k,edge[i].to); 37 } 38 void up(int k){ 39 f[k]=max(f[L],f[R]); 40 sum[k]=sum[L]+sum[R]; 41 } 42 void upd(int k,int x){ 43 tag[k]+=x; 44 f[k]+=x; 45 sum[k]+=x*val[k]; 46 } 47 void down(int k){ 48 upd(L,tag[k]); 49 upd(R,tag[k]); 50 tag[k]=0; 51 } 52 void build(int k,int l,int r){ 53 if (l==r){ 54 val[k]=dep[idfn[l]]-dep[fa[idfn[l]]]; 55 return; 56 } 57 build(L,l,mid); 58 build(R,mid+1,r); 59 val[k]=val[L]+val[R]; 60 } 61 void update(int k,int l,int r,int x,int y,int z){ 62 if ((l>y)||(x>r))return; 63 if ((x<=l)&&(r<=y)){ 64 upd(k,z); 65 return; 66 } 67 down(k); 68 update(L,l,mid,x,y,z); 69 update(R,mid+1,r,x,y,z); 70 up(k); 71 } 72 void update(int k,int x){ 73 while (k){ 74 update(1,1,n,dfn[top[k]],dfn[k],x); 75 k=fa[top[k]]; 76 } 77 } 78 int find(int k,int l,int r){ 79 if (l==r)return l; 80 down(k); 81 if (2*f[R]>D)return find(R,mid+1,r); 82 return find(L,l,mid); 83 } 84 ll query(int k,int l,int r,int x,int y){ 85 if ((l>y)||(x>r))return 0; 86 if ((x<=l)&&(r<=y))return sum[k]; 87 down(k); 88 return query(L,l,mid,x,y)+query(R,mid+1,r,x,y); 89 } 90 ll query(int k){ 91 ll ans=0; 92 while (k){ 93 ans+=query(1,1,n,dfn[top[k]],dfn[k]); 94 k=fa[top[k]]; 95 } 96 return ans; 97 } 98 ll calc(int k){ 99 return ans+1LL*D*dep[k]-2*query(k); 100 } 101 int main(){ 102 scanf("%d%d",&n,&m); 103 memset(head,-1,sizeof(head)); 104 for(int i=1;i<n;i++){ 105 scanf("%d%d%d",&x,&y,&z); 106 add(x,y,z); 107 add(y,x,z); 108 } 109 dfs1(1,0,0); 110 dfs2(1,0,1); 111 build(1,1,n); 112 for(int i=1;i<=m;i++){ 113 scanf("%d%d",&x,&y); 114 D+=y; 115 ans+=1LL*dep[x]*y; 116 update(x,y); 117 printf("%lld\n",calc(idfn[find(1,1,n)])); 118 } 119 }