直接点分树+线段树,对点分树上每一个节点维护子树内所有点到其的距离,需要支持子树修改(因此要用dfs序+线段树)以及区间最大值查询
对于查询,先在根节点的线段树中找到距离根节点最远的点,再枚举其与另一个点在点分树上的lca,同时查询区间最大值
总复杂度为$o(nlog^{2}n)$,会被卡常(惨惨),但支持负边权QAQ
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 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; 10 ll len; 11 }edge[N<<1]; 12 struct Data{ 13 int n; 14 map<int,int>dfn,sz,bl; 15 vector<int>v; 16 vector<ll>f,tag; 17 void build(int k,int l,int r){ 18 while (f.size()<=k){ 19 f.push_back(0); 20 tag.push_back(0); 21 } 22 if (l==r)return; 23 build(L,l,mid); 24 build(R,mid+1,r); 25 } 26 void update(int k,int l,int r,int x,int y,ll z){ 27 if ((l>y)||(x>r))return; 28 if ((x<=l)&&(r<=y)){ 29 tag[k]+=z,f[k]+=z; 30 return; 31 } 32 update(L,l,mid,x,y,z); 33 update(R,mid+1,r,x,y,z); 34 f[k]=max(f[L],f[R])+tag[k]; 35 } 36 ll query(int k,int l,int r,int x,int y){ 37 if ((l>y)||(x>r))return 0; 38 if ((x<=l)&&(r<=y))return f[k]; 39 return max(query(L,l,mid,x,y),query(R,mid+1,r,x,y))+tag[k]; 40 } 41 int find(int k,int l,int r,int x,int y,ll z){ 42 if ((l>y)||(x>r)||(f[k]<z))return 0; 43 if (l==r)return l; 44 int ans=find(L,l,mid,x,y,z-tag[k]); 45 if (ans)return ans; 46 return find(R,mid+1,r,x,y,z-tag[k]); 47 } 48 void update(int x,ll y){ 49 update(1,1,n,dfn[x],dfn[x]+sz[x]-1,y); 50 } 51 ll query(int k){ 52 return query(1,1,n,dfn[k],dfn[k]+sz[k]-1); 53 } 54 int find(int k){ 55 return v[find(1,1,n,dfn[k],dfn[k]+sz[k]-1,query(k))-1]; 56 } 57 ll query_one(int k){ 58 return query(1,1,n,dfn[k],dfn[k]); 59 } 60 ll query_other(int k){ 61 k=bl[k]; 62 return max(query(1,1,n,1,dfn[k]-1),query(1,1,n,dfn[k]+sz[k],n)); 63 } 64 }a[N]; 65 int E,n,q,rt,x,y,head[N],sz[N],vis[N],fa[N]; 66 ll w,z,ans; 67 void add(int x,int y,ll z){ 68 edge[E].nex=head[x]; 69 edge[E].to=y; 70 edge[E].len=z; 71 head[x]=E++; 72 } 73 void get_sz(int k,int fa){ 74 sz[k]=1; 75 for(int i=head[k];i!=-1;i=edge[i].nex) 76 if ((!vis[edge[i].to])&&(edge[i].to!=fa)){ 77 get_sz(edge[i].to,k); 78 sz[k]+=sz[edge[i].to]; 79 } 80 } 81 void get_rt(int k,int fa,int s){ 82 int mx=s-sz[k]; 83 for(int i=head[k];i!=-1;i=edge[i].nex) 84 if ((!vis[edge[i].to])&&(edge[i].to!=fa)){ 85 get_rt(edge[i].to,k,s); 86 mx=max(mx,sz[edge[i].to]); 87 } 88 if (mx<=s/2)rt=k; 89 } 90 void get_data(int k,int fa,int rt,int x){ 91 if (fa==rt)x=k; 92 a[rt].dfn[k]=++a[rt].n; 93 a[rt].sz[k]=1; 94 a[rt].bl[k]=x; 95 a[rt].v.push_back(k); 96 for(int i=head[k];i!=-1;i=edge[i].nex) 97 if ((!vis[edge[i].to])&&(edge[i].to!=fa)){ 98 get_data(edge[i].to,k,rt,x); 99 a[rt].sz[k]+=a[rt].sz[edge[i].to]; 100 } 101 } 102 void dfs(int k,int f){ 103 get_sz(k,0); 104 get_rt(k,0,sz[k]); 105 fa[rt]=f; 106 get_data(rt,0,rt,0); 107 a[rt].build(1,1,a[rt].n); 108 vis[rt]=1; 109 int r=rt; 110 for(int i=head[rt];i!=-1;i=edge[i].nex) 111 if (!vis[edge[i].to])dfs(edge[i].to,r); 112 } 113 void update(int x,int y,ll z){ 114 if (a[y].dfn[x])swap(x,y); 115 for(int i=x;i;i=fa[i]){ 116 if (a[i].dfn[x]>a[i].dfn[y])swap(x,y); 117 a[i].update(y,z); 118 } 119 } 120 ll query(){ 121 int x=a[rt].find(rt); 122 ll ans=a[x].query(x); 123 for(int i=x;fa[i];i=fa[i])ans=max(ans,a[fa[i]].query_other(i)+a[fa[i]].query_one(x)); 124 return ans; 125 } 126 int main(){ 127 scanf("%d%d%lld",&n,&q,&w); 128 memset(head,-1,sizeof(head)); 129 for(int i=1;i<n;i++){ 130 scanf("%d%d%lld",&x,&y,&z); 131 add(x,y,z); 132 add(y,x,z); 133 } 134 dfs(1,0); 135 for(int i=1;i<=n;i++) 136 if (!fa[i])rt=i; 137 for(int i=0;i<E;i+=2)update(edge[i].to,edge[i^1].to,edge[i].len); 138 for(int i=1;i<=q;i++){ 139 scanf("%d%lld",&x,&z); 140 x=(x+ans)%(n-1); 141 z=(z+ans)%w; 142 update(edge[x<<1].to,edge[(x<<1)^1].to,z-edge[x<<1].len); 143 edge[x<<1].len=z; 144 ans=query(); 145 printf("%lld ",ans); 146 } 147 return 0; 148 }
我们在每一个点入栈、出栈以及向下搜索时将其加入序列,并记此序列为$a_{i}$,序列长度为$2n-1$
令$dep_{x}$为$a_{x}$的深度,联系tarjan求lca的结论,不难得到答案即$sum_{1le lle mle r<2n}dep_{l}+dep_{r}-2dep_{m}$
修改即对$dep_{x}$区间修改,考虑使用线段树维护
下面,需要用线段树维护这个最大值,考虑先选$m$,那么最大的$dep_{x}$总是会被选的(也可以联系直径的结论,而且这个最大值的位置也是任意的)
再对于线段树的区间$[l,r]$,来维护$max_{lle xle yle r}dep_{x}-2dep_{y}$和$max_{lle xle yle r}dep_{y}-2dep_{x}$,通过附加维护区间最大值和最小值可以容易的得到
由此,复杂度为$o(nlog n)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define ll long long 5 #define oo 2e18 6 #define L (k<<1) 7 #define R (L+1) 8 #define mid (l+r>>1) 9 struct Edge{ 10 int nex,to; 11 ll len; 12 }edge[N<<1]; 13 struct Data{ 14 ll mx,mn,val1,val2,tag; 15 }f[N<<3]; 16 int E,n,q,x,y,head[N],dfn[N],l[N],r[N],a[N<<1]; 17 ll z,w,ans; 18 void add(int x,int y,ll z){ 19 edge[E].nex=head[x]; 20 edge[E].to=y; 21 edge[E].len=z; 22 head[x]=E++; 23 } 24 void dfs(int k,int fa){ 25 dfn[k]=++dfn[0]; 26 l[k]=a[0]+1; 27 for(int i=head[k];i!=-1;i=edge[i].nex) 28 if (edge[i].to!=fa){ 29 a[++a[0]]=k; 30 dfs(edge[i].to,k); 31 } 32 a[++a[0]]=k; 33 r[k]=a[0]; 34 } 35 Data merge(Data x,Data y){ 36 Data ans; 37 ans.mx=max(x.mx,y.mx); 38 ans.mn=min(x.mn,y.mn); 39 ans.val1=max(max(x.val1,y.val1),x.mx-2*y.mn); 40 ans.val2=max(max(x.val2,y.val2),y.mx-2*x.mn); 41 return ans; 42 } 43 void upd(int k,ll x){ 44 f[k].tag+=x; 45 f[k].mx+=x; 46 f[k].mn+=x; 47 f[k].val1-=x; 48 f[k].val2-=x; 49 } 50 void down(int k){ 51 upd(L,f[k].tag); 52 upd(R,f[k].tag); 53 f[k].tag=0; 54 } 55 void build(int k,int l,int r){ 56 f[k]=Data{0,0,0,0,0}; 57 if (l==r)return; 58 build(L,l,mid); 59 build(R,mid+1,r); 60 } 61 void update(int k,int l,int r,int x,int y,ll 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 f[k]=merge(f[L],f[R]); 71 } 72 int find(int k,int l,int r){ 73 if (l==r)return l; 74 down(k); 75 if (f[k].mx==f[L].mx)return find(L,l,mid); 76 return find(R,mid+1,r); 77 } 78 Data query(int k,int l,int r,int x,int y){ 79 if ((l>y)||(x>r))return f[0]; 80 if ((x<=l)&&(r<=y))return f[k]; 81 down(k); 82 return merge(query(L,l,mid,x,y),query(R,mid+1,r,x,y)); 83 } 84 ll query(){ 85 int x=find(1,1,2*n-1); 86 return query(1,1,2*n-1,x,x).mx+max(query(1,1,2*n-1,1,x).val1,query(1,1,2*n-1,x,2*n-1).val2); 87 } 88 int main(){ 89 scanf("%d%d%lld",&n,&q,&w); 90 memset(head,-1,sizeof(head)); 91 for(int i=1;i<n;i++){ 92 scanf("%d%d%lld",&x,&y,&z); 93 add(x,y,z); 94 add(y,x,z); 95 } 96 dfs(1,0); 97 f[0].mn=oo; 98 f[0].val1=f[0].val2=-oo; 99 build(1,1,2*n-1); 100 for(int i=0;i<E;i+=2){ 101 int a=edge[i].to,b=edge[i^1].to; 102 if (dfn[a]>dfn[b])swap(a,b); 103 update(1,1,2*n-1,l[b],r[b],edge[i].len); 104 } 105 for(int i=1;i<=q;i++){ 106 scanf("%d%lld",&x,&z); 107 x=(x+ans)%(n-1); 108 z=(z+ans)%w; 109 int a=edge[x<<1].to,b=edge[(x<<1)^1].to; 110 if (dfn[a]>dfn[b])swap(a,b); 111 update(1,1,2*n-1,l[b],r[b],z-edge[x<<1].len); 112 edge[x<<1].len=z; 113 ans=query(); 114 printf("%lld ",ans); 115 } 116 }