1. 程式人生 > >【BZOJ1146】網路管理(CTSC2008)-樹狀陣列+主席樹

【BZOJ1146】網路管理(CTSC2008)-樹狀陣列+主席樹

測試地址:網路管理 做法: 本題需要用到樹狀陣列+主席樹。 經典的帶修改樹上路徑第kk大問題,不過我太菜了居然忘了有樹上主席樹這個東西… 不帶修改的話能用樹上主席樹做,那麼帶修改怎麼辦呢?因為一次修改會影響一棵子樹上的所有線段樹,所以我們還是把樹拍成DFS序,就變成區間修改了。注意到查詢的時候只是查單棵線段樹,因此可以運用差分的方法,把上述操作變成單點修改,字首和求和,這個就用樹狀陣列套主席樹(準確上來講算樹狀陣列套動態開點線段樹?)就可以統計修改的貢獻了(即變成單次修改/查詢logn\log n棵線段樹)。注意原來點的貢獻和修改的貢獻是在不同的結構上統計的,一個是在樹上主席樹上統計,一個是在樹狀陣列套線段樹上統計。在二分的時候,把所有帶貢獻的線段樹點列出來,每次算貢獻的時候都掃一遍,向下走的時候所有點一起走即可。這樣我們就以O

(nlog2n)O(n\log^2n)的時間複雜度解決了這個問題。 寫起來挺複雜,但也不是太難,居然1A了,信心獲得增長。 以下是本人程式碼:

#include <bits/stdc++.h>
using namespace std;
int n,q,m,tot=0,val[100010],tote=0,first[100010]={0};
int pos[200010],k[100010],a[100010],b[100010];
int fa[100010][20]={0},dep[100010]={0},in[100010],out[100010],tim=0;
int seg[10000010]={0},ch[10000010][2]={0},rt[200010]={0};
int totp,
p[510],type[510]; struct edge { int v,next; }e[200010]; struct forsort { bool type; int id,val; }f[200010]; void insert(int a,int b) { e[++tote].v=b; e[tote].next=first[a]; first[a]=tote; } void pushup(int v) { seg[v]=seg[ch[v][0]]+seg[ch[v][1]]; } void insert(int &v,int last,int l,int r,int x) {
v=++tot; seg[v]=seg[last]; ch[v][0]=ch[last][0]; ch[v][1]=ch[last][1]; if (l==r) {seg[v]++;return;} int mid=(l+r)>>1; if (x<=mid) insert(ch[v][0],ch[last][0],l,mid,x); else insert(ch[v][1],ch[last][1],mid+1,r,x); pushup(v); } void modify(int &v,int l,int r,int x,int d) { if (!v) v=++tot; if (l==r) {seg[v]+=d;return;} int mid=(l+r)>>1; if (x<=mid) modify(ch[v][0],l,mid,x,d); else modify(ch[v][1],mid+1,r,x,d); pushup(v); } void dfs(int v) { in[v]=++tim; insert(rt[v],rt[fa[v][0]],1,m,val[v]); for(int i=first[v];i;i=e[i].next) if (e[i].v!=fa[v][0]) { fa[e[i].v][0]=v; dep[e[i].v]=dep[v]+1; dfs(e[i].v); } out[v]=tim; } int lowbit(int x) { return x&(-x); } void Add(int v,int x,int d) { for(int i=v;i<=n;i+=lowbit(i)) modify(rt[n+i],1,m,x,d); } void insert_p(int v,int d) { if (!v) return; p[++totp]=v,type[totp]=d; } void Sum(int v,int d) { for(int i=v;i;i-=lowbit(i)) insert_p(rt[n+i],d); } void query(int k) { int l=1,r=m,s,mid; while(l!=r) { s=0,mid=(l+r)>>1; for(int i=1;i<=totp;i++) s+=seg[ch[p[i]][1]]*type[i]; if (s<k) { r=mid; for(int i=1;i<=totp;i++) p[i]=ch[p[i]][0]; k-=s; } else { l=mid+1; for(int i=1;i<=totp;i++) p[i]=ch[p[i]][1]; } } s=0; for(int i=1;i<=totp;i++) s+=seg[p[i]]*type[i]; if (s<k) printf("invalid request!\n"); else printf("%d\n",pos[l]); } bool cmp(forsort a,forsort b) { return a.val<b.val; } int lca(int a,int b) { if (dep[a]<dep[b]) swap(a,b); for(int i=18;i>=0;i--) if (dep[fa[a][i]]>=dep[b]) a=fa[a][i]; if (a==b) return a; for(int i=18;i>=0;i--) if (fa[a][i]!=fa[b][i]) a=fa[a][i],b=fa[b][i]; return fa[a][0]; } int main() { scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) { scanf("%d",&f[++tot].val); f[tot].type=0,f[tot].id=i; } for(int i=1;i<n;i++) { int a,b; scanf("%d%d",&a,&b); insert(a,b),insert(b,a); } for(int i=1;i<=q;i++) { scanf("%d%d%d",&k[i],&a[i],&b[i]); if (!k[i]) { f[++tot].type=1,f[tot].id=i; f[tot].val=b[i]; } } sort(f+1,f+tot+1,cmp); m=0; for(int i=1;i<=tot;i++) { if (i==1||f[i].val!=f[i-1].val) pos[++m]=f[i].val; if (f[i].type) b[f[i].id]=m; else val[f[i].id]=m; } tot=0; dep[1]=1; dfs(1); for(int i=1;i<=18;i++) for(int j=1;j<=n;j++) fa[j][i]=fa[fa[j][i-1]][i-1]; for(int i=1;i<=q;i++) { if (!k[i]) { Add(in[a[i]],val[a[i]],-1); Add(out[a[i]]+1,val[a[i]],1); val[a[i]]=b[i]; Add(in[a[i]],val[a[i]],1); Add(out[a[i]]+1,val[a[i]],-1); } else { totp=0; insert_p(rt[a[i]],1); insert_p(rt[b[i]],1); int g=lca(a[i],b[i]); insert_p(rt[g],-1); if (fa[g][0]) insert_p(rt[fa[g][0]],-1); Sum(in[a[i]],1),Sum(in[b[i]],1),Sum(in[g],-1); if (fa[g][0]) Sum(in[fa[g][0]],-1); query(k[i]); } } return 0; }