[loj3163]动态直径

直接点分树+线段树,对点分树上每一个节点维护子树内所有点到其的距离,需要支持子树修改(因此要用dfs序+线段树)以及区间最大值查询

对于查询,先在根节点的线段树中找到距离根节点最远的点,再枚举其与另一个点在点分树上的lca,同时查询区间最大值

总复杂度为$o(n\log^{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\n",ans); 
146     }
147     return 0;
148 } 
View Code

我们在每一个点入栈、出栈以及向下搜索时将其加入序列,并记此序列为$a_{i}$,序列长度为$2n-1$

令$dep_{x}$为$a_{x}$的深度,联系tarjan求lca的结论,不难得到答案即$\sum_{1\le l\le m\le r<2n}dep_{l}+dep_{r}-2dep_{m}$

修改即对$dep_{x}$区间修改,考虑使用线段树维护

下面,需要用线段树维护这个最大值,考虑先选$m$,那么最大的$dep_{x}$总是会被选的(也可以联系直径的结论,而且这个最大值的位置也是任意的)

再对于线段树的区间$[l,r]$,来维护$\max_{l\le x\le y\le r}dep_{x}-2dep_{y}$和$\max_{l\le x\le y\le r}dep_{y}-2dep_{x}$,通过附加维护区间最大值和最小值可以容易的得到

由此,复杂度为$o(n\log 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\n",ans);
115     }
116 } 
View Code

 

posted @ 2021-05-23 18:06  PYWBKTDA  阅读(132)  评论(0编辑  收藏  举报