2019icpc上海网络赛 A 线段树动态维护树的直径及其端点
题目链接:https://nanti.jisuanke.com/t/41398
队友的博客:https://blog.csdn.net/weixin_44059127/article/details/100941413
题意:给定一棵有 n 个结点的边权树,给定 m 次操作,①:C,ei,wi,修改 ei 条边权为 wi;②:Q,vi,询问 vi 到其他点的最长距离。(n, m <= 1e5)
首先,我们可以知道,对于静态的树我们可以通过两遍dfs求出直径及其端点。
然后距离某一点最远点一定是直径端点,这个就不说了。。。
所以问题变成了支持修改边权,维护树的直径和端点,以及求两点距离。
后者可以这样看:和树链剖分一样,先跑一遍dfs,这样就可以知道某个节点的及其子树,那么dis【u】+=x相当于u的子树的dis都+=x。所以节点的dis可以用差分加树状数组维护,这样就可以带修改dis了。然后两点距离直接lca跑出来。
对于前者,我们可以这样看:dfs时候,假如dfs u 节点,dfs(v,u)以后,在dfs的序列在加一个u进去(具体见代码) 所以现在u子树的dfs序就变成 u v1 。 。 。 。 u v2 。 。 。 。 。 u。。。。。
两点距离等于dis[ v1 ] + dis[ v2 ] - 2*dis[ lca( v1, v2 ) ] ,这里lca( v1,v2) 就是u。所以线段树维护区间最小值(也就是lca,因为v1和v2之间放了一个u),那么区间的两点最长距离也就是在dfs序上,一个u划分两边,u左边的最大值(dis[ v1 ] ) + u右边最大值(dis [ v2 ]) - 区间最小值( dis[ u ] )。
那么怎么保证u的划分呢? 我们可以用线段树维护区间最大值(mx),以及最大值-2*最大值右边的区间mi(lmx)还有最大值-2*最大值左边的区间mi(rmx),那么区间两点最长距离的区间合并也就是 左儿子lmx+右儿子mx 以及 右儿子rmx+左儿子mx。同时维护一下lmx,mx,rmx端点就好啦。
还有,变量名下标1表示线段树,2表示树状数组。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define inf 0x3f3f3f3f 5 #define pq priority_queue<int,vector<int>,greater<int> > 6 const int N=2e5+9; 7 struct edge{ 8 int to,nex; 9 ll w; 10 }e[N<<1]; 11 struct node{ 12 ll mx,mi,lmx,rmx,val,lazy; 13 int idl,idr,idmx; 14 int u,v; 15 }tr[N<<2]; 16 int h[N],f[N][25],dep[N],st2[N],ed2[N]; 17 ll tr2[N],dis[N]; 18 int rnk[N<<3],st1[N<<3],ed1[N<<3]; 19 int cnt=1,n,m,tot1=0,tot2=0; 20 void add(int u,int v,ll wi){ 21 e[++cnt]=(edge){v,h[u],wi}; 22 h[u]=cnt; 23 } 24 void dfs(int u,int fa){ 25 st1[u]=++tot1; st2[u]=++tot2; rnk[tot1]=u; 26 f[u][0]=fa; dep[u]=dep[fa]+1; 27 for(int i=1;i<=20;++i) f[u][i]=f[ f[u][i-1] ][i-1]; 28 for(int i=h[u];i;i=e[i].nex){ 29 int v=e[i].to; 30 if(v==fa) continue; 31 dis[v]=dis[u]+e[i].w; 32 dfs(v,u); 33 rnk[++tot1]=u; 34 } 35 ed1[u]=tot1; ed2[u]=tot2; 36 } 37 void push_up(int o){ 38 tr[o].mx=max(tr[o<<1].mx,tr[o<<1|1].mx); 39 tr[o].mi=min(tr[o<<1].mi,tr[o<<1|1].mi); 40 tr[o].lmx=max( max(tr[o<<1].lmx,tr[o<<1|1].lmx) , tr[o<<1].mx-2*tr[o<<1|1].mi); 41 tr[o].rmx=max( max(tr[o<<1].rmx,tr[o<<1|1].rmx) , tr[o<<1|1].mx-2*tr[o<<1].mi); 42 tr[o].val=max( max(tr[o<<1].val,tr[o<<1|1].val), max(tr[o<<1].lmx+tr[o<<1|1].mx,tr[o<<1].mx+tr[o<<1|1].rmx) ); 43 44 if(tr[o].lmx==tr[o<<1].lmx) tr[o].idl=tr[o<<1].idl; 45 else if(tr[o].lmx==tr[o<<1|1].lmx) tr[o].idl=tr[o<<1|1].idl; 46 else tr[o].idl=tr[o<<1].idmx; 47 48 if(tr[o].rmx==tr[o<<1].rmx) tr[o].idr=tr[o<<1].idr; 49 else if(tr[o].rmx==tr[o<<1|1].rmx) tr[o].idr=tr[o<<1|1].idr; 50 else tr[o].idr=tr[o<<1|1].idmx; 51 52 if(tr[o].mx==tr[o<<1].mx) tr[o].idmx=tr[o<<1].idmx; 53 else tr[o].idmx=tr[o<<1|1].idmx; 54 55 if(tr[o].val==tr[o<<1].val) tr[o].u=tr[o<<1].u,tr[o].v=tr[o<<1].v; 56 else if(tr[o].val==tr[o<<1|1].val) tr[o].u=tr[o<<1|1].u,tr[o].v=tr[o<<1|1].v; 57 else if(tr[o].val==tr[o<<1].lmx+tr[o<<1|1].mx) tr[o].u=tr[o<<1].idl,tr[o].v=tr[o<<1|1].idmx; 58 else tr[o].u=tr[o<<1].idmx,tr[o].v=tr[o<<1|1].idr; 59 } 60 void push_down(int o){ 61 if(tr[o].lazy){ 62 ll tem=tr[o].lazy; tr[o].lazy=0; 63 tr[o<<1].lazy+=tem; tr[o<<1|1].lazy+=tem; 64 tr[o<<1].mx+=tem; tr[o<<1].mi+=tem; tr[o<<1].lmx-=tem; tr[o<<1].rmx-=tem; 65 tr[o<<1|1].mx+=tem; tr[o<<1|1].mi+=tem; tr[o<<1|1].lmx-=tem; tr[o<<1|1].rmx-=tem; 66 } 67 } 68 void build(int o,int l,int r){ 69 tr[o].lazy=0; 70 if(l==r){ 71 tr[o].idl=tr[o].idr=tr[o].idmx=rnk[l]; 72 ll d=dis[rnk[l]]; 73 tr[o].mx=tr[o].mi=d; 74 tr[o].lmx=tr[o].rmx=-d; 75 tr[o].val=0; 76 tr[o].u=tr[o].v=rnk[l]; 77 return; 78 } 79 int m=(l+r)>>1; 80 build(o<<1,l,m); 81 build(o<<1|1,m+1,r); 82 push_up(o); 83 } 84 void change(int o,int l,int r,int x,int y,ll w){ 85 if(x<=l && r<=y){ 86 tr[o].lazy+=w; tr[o].mx+=w; tr[o].mi+=w; 87 tr[o].lmx-=w; tr[o].rmx-=w; 88 return; 89 } 90 push_down(o); 91 int m=(l+r)>>1; 92 if(x<=m) change(o<<1,l,m,x,y,w); 93 if(y>m) change(o<<1|1,m+1,r,x,y,w); 94 push_up(o); 95 } 96 97 void add2(int x,ll v){ for(;x<=n;x+=x&(-x)) tr2[x]+=v; } 98 ll sum2(int x){ 99 ll res=0; 100 for(;x;x-=x&(-x)) res+=tr2[x]; 101 return res; 102 } 103 104 int lca(int u,int v){ 105 if(dep[u]<dep[v]) swap(u,v); 106 for(int i=20;i>=0;--i){ 107 if(dep[f[u][i]] >= dep[v]) u=f[u][i]; 108 } 109 if(u==v) return u; 110 for(int i=20;i>=0;--i){ 111 if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i]; 112 } 113 return f[u][0]; 114 } 115 ll cal(int u,int v){ 116 int fa=lca(u,v); 117 ll du=sum2(st2[u]),dv=sum2(st2[v]),dfa=sum2(st2[fa]); 118 return du+dv-2*dfa; 119 } 120 121 int main(){ 122 scanf("%d",&n); 123 for(int i=1;i<n;++i){ 124 int u,v; ll w; scanf("%d %d %lld",&u,&v,&w); 125 add(u,v,w); add(v,u,w); 126 } 127 dfs(1,0); 128 for(int i=1;i<=n;++i){ add2(st2[i],dis[i]); add2(st2[i]+1,-dis[i]); } 129 build(1,1,tot1); 130 scanf("%d",&m); 131 char s[3]; 132 for(int i=1;i<=m;++i){ 133 scanf("%s",s); 134 if(s[0]=='Q'){ 135 int x; scanf("%d",&x); 136 int u=tr[1].u,v=tr[1].v; 137 printf("%lld\n",max(cal(u,x),cal(v,x))); 138 } 139 else{ 140 int x;ll y; scanf("%d %lld",&x,&y); 141 x*=2; 142 int u=e[x].to,v=e[x|1].to; 143 u= dep[u]>dep[v] ? u : v ; 144 change(1,1,tot1,st1[u],ed1[u],y-e[x].w); 145 add2(st2[u],y-e[x].w); add2(ed2[u]+1,e[x].w-y); 146 e[x].w=e[x|1].w=y; 147 } 148 } 149 return 0; 150 }