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(" "); 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 ",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! "); 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 ",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 ",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 */
题目链接: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即可。
树链剖分+树套树。