BZOJ2588Count on a tree——LCA+主席樹
阿新 • • 發佈:2018-07-12
div map 相加 sam cstring 換行符 cpp swap \n
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
0 5 2
10 5 3
11 5 4
110 8 2
8
9
105
7
最後附上代碼。
題目描述
給定一棵N個節點的樹,每個點有一個權值,對於M個詢問(u,v,k),你需要回答u xor lastans和v這兩個節點間第K小的點權。其中lastans是上一個詢問的答案,初始為0,即第一個詢問的u是明文。輸入
第一行兩個整數N,M。 第二行有N個整數,其中第i個整數表示點i的權值。 後面N-1行每行兩個整數(x,y),表示點x到點y有一條邊。 最後M行每行兩個整數(u,v,k),表示一組詢問。輸出
M行,表示每個詢問的答案。最後一個詢問不輸出換行符
樣例輸入
8 5105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 7
4 8
2 5 1
0 5 2
10 5 3
11 5 4
110 8 2
樣例輸出
28
9
105
7
提示
HINT: N,M<=100000 查詢一個路徑上第k小,就相當於查詢序列上區間第k小,可以想到用主席樹維護。但這道題是在樹上完成的操作,所以並不能像平常主席樹一樣只用r時刻減掉l-1時刻的線段樹查詢。對於樹上的路徑(以x和y之間的路徑為例),可以把它分成兩部分:x到lca和y到lca。這樣整條路徑上的信息就可以通過這兩條鏈相加得到。所以直接用x時刻線段樹+y時刻線段樹-lca時刻線段樹-lca的父節點時刻線段樹就得到路徑上狀態。每個時刻線段樹由它的父節點時刻線段樹轉移過來。#include<map> #include<set> #include<queue> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define mid (L+R)/2 using namespace std; int ans; int tot; int cnt; int anc; int n,m,q; int x,y,z; int d[100010]; int v[100010]; int h[100010]; int l[3000010]; int r[3000010]; int to[200010]; int head[100010]; int next[200010]; int sum[3000010]; int root[100010]; int f[100010][20]; map<int,int>b; void add(int x,int y) { tot++; next[tot]=head[x]; head[x]=tot; to[tot]=y; } int lca(int x,int y) { if(d[x]<d[y]) { swap(x,y); } int dep=d[x]-d[y]; for(int i=0;i<=19;i++) { if((dep&(1<<i))!=0) { x=f[x][i]; } } if(x==y) { return x; } for(int i=19;i>=0;i--) { if(f[x][i]!=f[y][i]) { x=f[x][i]; y=f[y][i]; } } return f[x][0]; } int updata(int pre,int L,int R,int k) { int rt=++cnt; l[rt]=l[pre]; r[rt]=r[pre]; sum[rt]=sum[pre]+1; if(L==R) { return rt; } else { if(k<=mid) { l[rt]=updata(l[pre],L,mid,k); } else { r[rt]=updata(r[pre],mid+1,R,k); } } return rt; } int query(int x,int y,int anc,int fa,int L,int R,int k) { if(L==R) { return b[L]; } int num=sum[l[x]]+sum[l[y]]-sum[l[anc]]-sum[l[fa]]; if(num>=k) { return query(l[x],l[y],l[anc],l[fa],L,mid,k); } else { return query(r[x],r[y],r[anc],r[fa],mid+1,R,k-num); } } void dfs(int x,int fa) { d[x]=d[fa]+1; int k=lower_bound(h+1,h+1+m,v[x])-h; b[k]=v[x]; root[x]=updata(root[fa],1,n,k); for(int i=1;i<=19;i++) { f[x][i]=f[f[x][i-1]][i-1]; } for(int i=head[x];i;i=next[i]) { if(to[i]!=fa) { f[to[i]][0]=x; dfs(to[i],x); } } } int main() { scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) { scanf("%d",&v[i]); h[i]=v[i]; } sort(h+1,h+1+n); m=unique(h+1,h+1+n)-h-1; for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs(1,0); for(int i=1;i<=q;i++) { scanf("%d%d%d",&x,&y,&z); x=x^ans; anc=lca(x,y); ans=query(root[x],root[y],root[anc],root[f[anc][0]],1,n,z); printf("%d\n",ans); } }
BZOJ2588Count on a tree——LCA+主席樹