洛谷P4315 月下“毛景树” 边权树剖+双标记

题目链接

做这道题的时候,乍一看很熟悉,之前考试时也做过类似的题。这道题树剖+线段树是个人都看得出来,不过覆盖标记和加标记同时下放是这道题最坑的地方。当时考试的时候就被这东西搞惨了。

做法:树剖维护边权的时候等效于维护两点之间深度较深的点的点权,这很好理解。

在修改和查询的时候,注意到这张图,我们假定修改F和G路径里的边权。这个时候我们同一般的树剖来跳,最后当他们在同一条链上时,其中有一个必然为另一个的祖先,但我们不能去改祖先的维护的那个点值,因为那个边没有在F->G的路径上。所以利用DFS序的连续性,要将祖先的DFS序+1,这样就改不到祖先那里去,只能改路径上的边权。同时下放两个标记的时候,覆盖标记的优先级是比加标记要大的,所以我们必须要先下放覆盖标记,而一旦有了覆盖标记,之前的所有标记全部作废,所以我们还要把加标记赋为0。并且要注意覆盖标记初始值为-1。

代码如下:

 

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int maxn=1e6+7;
  4 int n,x,y,v;
  5 struct node{
  6     int nxt,to,val,fro;
  7 }edge[maxn*3];
  8 struct node1{
  9     int l,r,lazy1,lazy2;
 10     long long sum,mx;
 11 }tree[maxn*4];
 12 int head[maxn],cnt;
 13 void add(int x,int y,int v){
 14     edge[++cnt].nxt=head[x];
 15     edge[cnt].fro=x;
 16     edge[cnt].to=y;
 17     edge[cnt].val=v;
 18     head[x]=cnt;
 19 }
 20 long long max(long long a,long long b){
 21     return a>b?a:b;
 22 }
 23 int dep[maxn],fa[maxn],top[maxn],size[maxn],son[maxn],id[maxn],rev[maxn],w[maxn];
 24 void dfs1(int x,int f){
 25     fa[x]=f;
 26     dep[x]=dep[f]+1;
 27     size[x]=1;
 28     int maxson=-1;
 29     for(int i=head[x];i;i=edge[i].nxt){
 30         int go=edge[i].to;
 31         if(go==fa[x]) continue;
 32         w[go]=edge[i].val;
 33         dfs1(go,x);
 34         size[x]+=size[go];
 35         if(size[go]>maxson){
 36             maxson=size[go];
 37             son[x]=go;
 38         }
 39     }
 40 }
 41 int Time;
 42 void dfs2(int x,int topf){
 43     top[x]=topf;
 44     id[x]=++Time;
 45     rev[id[x]]=w[x];
 46     if(!son[x]) return;
 47     dfs2(son[x],topf);
 48     for(int i=head[x];i;i=edge[i].nxt){
 49         int go=edge[i].to;
 50         if(son[x]==go||go==fa[x]) continue;
 51         dfs2(go,go);
 52     }
 53 }
 54 void build(int now,int l,int r){
 55     tree[now].l=l,tree[now].r=r,tree[now].lazy1=-1,tree[now].lazy2=0;
 56     if(l==r){
 57         tree[now].mx=rev[l];
 58         return;
 59     }
 60     int mid=(l+r)>>1;
 61     build(now<<1,l,mid);
 62     build(now<<1|1,mid+1,r);
 63     tree[now].mx=max(tree[now<<1].mx,tree[now<<1|1].mx);
 64 }
 65 void pushdown(int now){
 66     if(tree[now].lazy1!=-1){
 67         tree[now<<1].mx=tree[now].lazy1;
 68         tree[now<<1|1].mx=tree[now].lazy1; 
 69         tree[now<<1].lazy1=tree[now].lazy1;
 70         tree[now<<1|1].lazy1=tree[now].lazy1;
 71         tree[now].lazy1=-1;
 72         tree[now<<1].lazy2=tree[now<<1|1].lazy2=0;
 73     }
 74     if(tree[now].lazy2){
 75         tree[now<<1].mx+=tree[now].lazy2;
 76         tree[now<<1|1].mx+=tree[now].lazy2;
 77         tree[now<<1].lazy2+=tree[now].lazy2;
 78         tree[now<<1|1].lazy2+=tree[now].lazy2;
 79         tree[now].lazy2=0;
 80     }
 81 }
 82 void update1(int now,int l,int r,int v){
 83     if(tree[now].l>=l&&tree[now].r<=r){
 84         tree[now].lazy2+=v;
 85         tree[now].mx+=v;
 86         return; 
 87     }
 88     pushdown(now);
 89     int mid=(tree[now].l+tree[now].r)>>1;
 90     if(l<=mid) update1(now<<1,l,r,v);
 91     if(r>mid) update1(now<<1|1,l,r,v);
 92     tree[now].mx=max(tree[now<<1].mx,tree[now<<1|1].mx); 
 93 }
 94 void update2(int now,int l,int r,int v){
 95     if(tree[now].l>=l&&tree[now].r<=r){
 96         tree[now].mx=v;
 97         tree[now].lazy1=v;
 98         tree[now].lazy2=0;
 99         return;
100     }
101     pushdown(now);
102     int mid=(tree[now].l+tree[now].r)>>1;
103     if(l<=mid) update2(now<<1,l,r,v);
104     if(r>mid) update2(now<<1|1,l,r,v);
105     tree[now].mx=max(tree[now<<1].mx,tree[now<<1|1].mx);
106 }
107 long long query(int now,int l,int r){
108     if(tree[now].l>=l&&tree[now].r<=r) return tree[now].mx;
109     pushdown(now);
110     int mid=(tree[now].l+tree[now].r)>>1;
111     long long wa=0;
112     if(l<=mid) wa=max(wa,query(now<<1,l,r));
113     if(r>mid) wa=max(wa,query(now<<1|1,l,r));
114     return wa; 
115 }
116 void link1(int x,int y,int v){
117     while(top[x]!=top[y]){
118         if(dep[top[x]]<dep[top[y]]) swap(x,y);
119         update1(1,id[top[x]],id[x],v);
120         x=fa[top[x]];
121     }
122     if(dep[x]<dep[y]) swap(x,y);
123     update1(1,id[y]+1,id[x],v);
124 }
125 void link2(int x,int y,int v){
126     while(top[x]!=top[y]){
127         if(dep[top[x]]<dep[top[y]]) swap(x,y);
128         update2(1,id[top[x]],id[x],v);
129         x=fa[top[x]];
130     }
131     if(dep[x]<dep[y]) swap(x,y);
132     update2(1,id[y]+1,id[x],v);
133 }
134 long long linkquery(int x,int y){
135     if(x==y) return 0;
136     long long ans=0;
137     while(top[x]!=top[y]){
138         if(dep[top[x]]<dep[top[y]]) swap(x,y);
139         ans=max(ans,query(1,id[top[x]],id[x]));
140         x=fa[top[x]];
141     }
142     if(dep[x]<dep[y]) swap(x,y);
143     ans=max(ans,query(1,id[y]+1,id[x]));
144     return ans;
145 }
146 char opt[5];
147 int u,j,a,k;
148 int main(){
149     scanf("%d",&n);
150     for(int i=1;i<n;i++){
151         scanf("%d%d%d",&x,&y,&v);
152         add(x,y,v);add(y,x,v);
153     }
154     dfs1(1,0);
155     dfs2(1,1);
156     build(1,1,n); 
157     while(1){
158         scanf("%s",opt);
159         if(opt[0]=='C'&&opt[1]=='h'){
160             scanf("%d%d",&k,&a);
161             int x;
162             x=dep[edge[k*2].fro]>dep[edge[k*2].to]?id[edge[k*2].fro]:id[edge[k*2].to];
163             update2(1,x,x,a);
164         }
165         if(opt[0]=='C'&&opt[1]=='o'){
166             scanf("%d%d%d",&u,&j,&a);
167             link2(u,j,a);
168         }
169         if(opt[0]=='A'){
170             scanf("%d%d%d",&u,&j,&a);
171             link1(u,j,a);
172         }
173         if(opt[0]=='M'){
174             scanf("%d%d",&u,&j);
175             printf("%lld\n",linkquery(u,j));
176         }
177         if(opt[0]=='S') break;
178     }
179     return 0;
180 }
View Code

 

posted @ 2019-08-11 17:30  JBLee  阅读(239)  评论(0编辑  收藏  举报