bzoj1146: [CTSC2008]网络管理Network

  1 #include <iostream>
  2 #include <iostream>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <cmath>
  6 using namespace std;
  7 #define maxn 80005
  8 #define maxk 3200005
  9 #define maxm 160005
 10 #define inf 100000000
 11 
 12 int n,q,sum,a[maxn],root[maxn<<2];
 13 struct Gsegment{
 14     int tot,fa[maxk],son[maxk][2],val[maxk],times[maxk],size[maxk];
 15     void prepare(){tot=0,memset(times,0,sizeof(times));}
 16     int which(int x){return son[fa[x]][1]==x;}
 17     void update(int x){
 18         size[x]=size[son[x][0]]+size[son[x][1]]+times[x];
 19     }
 20     void rotata(int x){
 21         int y=fa[x],d=which(x),dd=which(y);
 22         if (fa[y]) son[fa[y]][dd]=x; fa[x]=fa[y];
 23         fa[son[x][d^1]]=y,son[y][d]=son[x][d^1];
 24         fa[y]=x,son[x][d^1]=y,update(y);
 25     }
 26     void splay(int x,int goal,int op){
 27         while (fa[x]!=goal){
 28             if (fa[fa[x]]==goal) rotata(x);
 29             else if (which(x)==which(fa[x])) rotata(fa[x]),rotata(x);
 30             else rotata(x),rotata(x);
 31         }
 32         update(x); if (goal==0) root[op]=x;
 33     }
 34     void insert(int k,int x){
 35         int y=root[k]; bool bo;
 36         if (y==0){
 37             root[k]=++tot,val[tot]=x,times[tot]=size[tot]=1,fa[tot]=son[tot][0]=son[tot][1]=0;
 38             return;
 39         }
 40         for (;;){
 41             bo=0;
 42             if (val[y]==x) times[y]++,size[y]++,bo=1,splay(y,0,k);
 43             else if (x<val[y]){
 44                 if (!son[y][0]) son[y][0]=++tot,val[tot]=x,size[tot]=times[tot]=1,fa[tot]=y,bo=1,splay(tot,0,k);
 45                 else y=son[y][0];
 46             }else{
 47                 if (!son[y][1]) son[y][1]=++tot,val[tot]=x,size[tot]=times[tot]=1,fa[tot]=y,bo=1,splay(tot,0,k);
 48                 else y=son[y][1];
 49             }
 50             if (bo==1) break;
 51         }
 52     }
 53     void query(int k,int x){
 54         int y=root[k]; if (y==0) return; bool bo;
 55         for (;;){
 56             bo=0;
 57             if (y==0) break;
 58             if (val[y]==x) bo=1,sum+=size[son[y][0]];
 59             else if (x<val[y]) y=son[y][0];
 60             else sum+=(size[son[y][0]]+times[y]),y=son[y][1];
 61             if (bo==1) break;
 62         }
 63     }
 64     int prep(int k,int x){
 65         splay(x,0,k);
 66         int y=son[x][0];
 67         while (son[y][1]) y=son[y][1];
 68         return y;
 69     }
 70     void DLT(int k,int x){
 71         int y=prep(k,x),z;
 72         if (y==0){
 73             splay(x,0,k);
 74             z=son[x][1];
 75             fa[z]=0,root[k]=z,son[x][0]=fa[x]=son[x][1]=times[x]=size[x]=0;
 76         }else{
 77             splay(y,0,k),splay(x,y,k),z=son[x][1];
 78             fa[z]=y,son[y][1]=z,fa[x]=son[x][0]=son[x][1]=size[x]=times[x]=0;
 79             update(y);
 80         }
 81     }
 82     void dlt(int k,int x){
 83         int y=root[k]; if (y==0) return; bool bo;
 84         for (;;){
 85             bo=0;
 86             if (val[y]==x){
 87                 if (times[y]>1) times[y]--,size[y]--,bo=1,splay(y,0,k);
 88                 else times[y]--,size[y]--,bo=1,DLT(k,y);
 89             }else if (x<val[y]) y=son[y][0];
 90             else y=son[y][1];
 91             if (bo==1) break;
 92         }
 93     }
 94 }Splay;//伸展树 
 95 struct Fsegment{
 96     void insert(int k,int l,int r,int x,int y){
 97         Splay.insert(k,y);
 98         if (l==r) return;
 99         int mid=(l+r)>>1;
100         if (x<=mid) insert(k*2,l,mid,x,y);
101         else insert(k*2+1,mid+1,r,x,y);
102     }
103     void query(int k,int l,int r,int x,int y,int z){
104         if (l>=x&&r<=y){
105             Splay.query(k,z);
106             return;
107         }int mid=(l+r)>>1;
108         if (x<=mid) query(k*2,l,mid,x,y,z);
109         if (y>mid) query(k*2+1,mid+1,r,x,y,z);
110     }
111     void change(int k,int l,int r,int x,int y){
112         Splay.dlt(k,y);
113         if (l==r) return;
114         int mid=(l+r)>>1;
115         if (x<=mid) change(k*2,l,mid,x,y);
116         else change(k*2+1,mid+1,r,x,y); 
117     }
118 }Line_tree;//线段树 
119 struct Tsegment{
120     int tot,temp,prep[maxm],son[maxm],hson[maxn],fa[maxn],now[maxn],bz[maxn][20],lo[maxn],top[maxn],size[maxn],deep[maxn],dfn[maxn];
121     void prepare(){
122         tot=0,temp=0,memset(now,0,sizeof(now));
123         memset(fa,0,sizeof(fa));
124         memset(deep,0,sizeof(deep));
125         for (int i=1;i<=maxn;i++) lo[i]=log2(i);
126     }
127     void add(int x,int y){
128         prep[++tot]=now[x],now[x]=tot,son[tot]=y;
129     }
130     void Add(int x,int y){add(x,y),add(y,x);}
131     void dfs1(int x){
132         deep[x]=deep[fa[x]]+1,size[x]=1,bz[x][0]=fa[x];
133         for (int i=now[x],so=son[i];i;i=prep[i],so=son[i]){
134             if (so!=fa[x]){
135                 fa[so]=x,dfs1(so),size[x]+=size[so];
136                 if (!hson[x]||size[so]>size[hson[x]]) hson[x]=so;
137             }
138         }
139     }
140     void dfs2(int x){
141         int v=hson[x];
142         if (v) dfn[v]=++temp,top[v]=top[x],dfs2(v);
143         for (int i=now[x],so=son[i];i;i=prep[i],so=son[i]){
144             if (so!=hson[x]&&so!=fa[x]){
145                 top[so]=so,dfn[so]=++temp,dfs2(so);
146             }
147         }
148     }
149     int lca(int x,int y){
150         if (x==y) return x;
151         if (deep[x]<deep[y]) swap(x,y);
152         while (deep[x]!=deep[y]){
153             x=bz[x][lo[deep[x]-deep[y]]];
154         }
155         if (x==y) return x;
156         while (bz[x][0]!=bz[y][0]){
157             for (int i=lo[deep[x]];i>=0;i--){
158                 if (bz[x][i]!=bz[y][i]){
159                     x=bz[x][i],y=bz[y][i];break;
160                 }
161             }
162         }
163         return bz[x][0];
164     }
165     void build(){
166         dfs1(1);
167         temp=0,dfn[1]=++temp,top[1]=1,dfs2(1);
168         for (int i=1;i<=17;i++){
169             for (int j=1;j<=n;j++){
170                 bz[j][i]=bz[bz[j][i-1]][i-1];
171             }
172         }
173 //        for (int i=1;i<=n;i++){
174 //            for (int j=0;j<=3;j++){
175 //                printf("%d ",bz[i][j]);
176 //            }
177 //            printf("\n");
178 //        }
179         for (int i=1;i<=n;i++) Line_tree.insert(1,1,n,dfn[i],a[i]);
180     }
181     int  Query(int x,int y,int z){
182         sum=0;
183         for (int t1=top[x],t2=top[y];t1!=t2;x=fa[t1],t1=top[x],t2=top[y]){
184             if (deep[t1]<deep[t2]) swap(t1,t2),swap(x,y);
185             Line_tree.query(1,1,n,dfn[t1],dfn[x],z);
186         }
187         if (deep[x]>deep[y]) swap(x,y);
188         Line_tree.query(1,1,n,dfn[x],dfn[y],z);
189         return sum;
190     }
191     void query(int x,int y,int z){
192 //        printf("%d %d %d\n",x,y,z);
193         int tmp=lca(x,y); bool bo=0;
194         if (deep[x]+deep[y]-2*deep[tmp]+1<z) bo=1,printf("invalid request!\n");
195         if (bo==1) return;
196         z=(deep[x]+deep[y]-2*deep[tmp]+1)-z+1;
197         int low=0,high=inf,mid,ans=0;
198         while (low<=high){
199             mid=(low+high)>>1;
200             if (Query(x,y,mid)+1<=z) ans=mid,low=mid+1;
201             else high=mid-1;
202         }
203         printf("%d\n",ans);
204     }
205     void change(int x,int y){
206         Line_tree.change(1,1,n,dfn[x],a[x]),a[x]=y,Line_tree.insert(1,1,n,dfn[x],a[x]);
207     }
208 }Tree;//树链剖分
209 
210 int main(){
211     scanf("%d%d",&n,&q);
212     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
213     int oppo,u,v;
214     Tree.prepare();
215     Splay.prepare();
216     for (int i=1;i<n;i++) scanf("%d%d",&u,&v),Tree.Add(u,v);
217     Tree.build();
218     while (q--){
219         scanf("%d%d%d",&oppo,&u,&v);
220 //        printf("%d %d %d\n",oppo,u,v);
221         if (oppo==0) Tree.change(u,v);
222         else Tree.query(u,v,oppo);
223     }
224     return 0; 
225 }
226 /*
227 5 5
228 5 1 2 3 4
229 3 1
230 2 1
231 4 3
232 5 3
233 2 4 5
234 0 1 2
235 2 2 3
236 2 1 4
237 3 3 5
238 
239 3
240 2
241 2
242 invalid request!
243 */
View Code

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1146

题目大意:给定一棵n个节点的树,每个点有一个权值,有q个操作,包括如下两种:

1.询问x,y节点的路径上第k大的权值,若没有k个节点,则输出invalid request!

2.修改某个节点的权值。

 

做法:如果只有操作1,我们考虑用可持久化线段树,毕竟求第k大嘛,那就成了这个题目 bzoj2588: Spoj 10628. Count on a tree,对于这个弱化版的题目,我们用可持久化线段树维护该点到根节点的路径上的权值,sumx+sumy-sumlca-sumfa【lca】即为x,y路径上的信息,然后用BST的性质二分一下就ok了。

但这题多了一个操作2,即修改某个点的权值,如果用之前的做法,那就会对以该点为根的子树的所有节点产生影响,复杂度极高。

我们考虑树链剖分+树套树(线段树套splay),线段树维护dfs序区间的点,对于每个线段树节点,套一个splay,维护这段dfs序区间中的权值。

对于修改操作,在所有包含该点dfs序的splay中先删除原来的权值,再加入新的权值。

对于询问操作,先转化为第k小,二分答案,树链剖分经典问题,若小于该权值的个数+1<=k,ans=mid,l=mid+1,否则r=mid-1;输出ans即可。

树链剖分+树套树。

posted @ 2016-05-29 10:48  oyzx~  阅读(244)  评论(0编辑  收藏  举报