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 }
View Code

猜你喜欢

转载自www.cnblogs.com/xiaobuxie/p/11545964.html