1. 程式人生 > >Spoj 10628. Count on a tree

Spoj 10628. Count on a tree

open class style pen 技術 += 初始 medium poj

Description

給定一棵N個節點的樹,每個點有一個權值,對於M個詢問(u,v,k),你需要回答u xor lastans和v這兩個節點間第K小的點權。其中lastans是上一個詢問的答案,初始為0,即第一個詢問的u是明文。

Input

第一行兩個整數N,M。 第二行有N個整數,其中第i個整數表示點i的權值。 後面N-1行每行兩個整數(x,y),表示點x到點y有一條邊。 最後M行每行兩個整數(u,v,k),表示一組詢問。

Output

M行,表示每個詢問的答案。最後一個詢問不輸出換行符

Sample Input

8 5
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

Sample Output

2
8
9
105
7

HINT

HINT:
N,M<=100000
暴力自重。。。

Source

鳴謝seter

思路

樹鏈剖分+主席樹,然後用一棵線段樹輔助查詢。

代碼實現

技術分享
#include<cstdio>
const int maxn=1e5+10;
inline int min_(int x,int
y){return x<y?x:y;} inline int max_(int x,int y){return x>y?x:y;} int h[maxn],hs,et[maxn<<1],en[maxn<<1]; int p[maxn],pf[maxn],pd[maxn],pt[maxn],pp[maxn],pps,psz[maxn],pws[maxn]; int s[maxn],ss; int rt[maxn],t[maxn<<4],ft[maxn<<4]; int n,m; int a,b,c,ans; void dfs1(int
k,int f,int d){ pf[k]=f,pd[k]=d,psz[k]=1; for(int i=h[k];i;i=en[i]) if(et[i]!=f){ dfs1(et[i],k,d+1); psz[k]+=psz[et[i]]; if(psz[et[i]]>psz[pws[k]]) pws[k]=et[i]; } } void dfs2(int k,int t){ s[++pps]=p[k],pp[k]=pps; if(pws[k]) dfs2(pws[k],t); for(int i=h[k];i;i=en[i]) if(et[i]!=pf[k]&&et[i]!=pws[k]) dfs2(et[i],et[i]); } void build(int k,int l,int r){ if(l==r){ t[k]=s[++ss]; return; } int t } void clear(){ } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&p[i]); for(int i=1;i<n;i++){ scanf("%d%d",&a,&b); ++hs,et[hs]=b,en[hs]=h[a],h[a]=hs; ++hs,et[hs]=a,en[hs]=h[b],h[b]=hs; } dfs1(1,1,1); dfs2(1,1); for(int i=1;i<=m;i++){ scanf("%d%d%d",&a,&b,&c);a^=ans; clear(); printf("%d\n",ans); } return 0; }
並沒有寫完。。。

Spoj 10628. Count on a tree