2588: Spoj 10628. Count on a tree

2588: Spoj 10628. Count on a tree

Time Limit: 12 Sec  Memory Limit: 128 MB
Submit: 5766  Solved: 1374
[Submit][Status][Discuss]

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

/*
树上第K大.
对于每一个节点以key(权值)为下标
用一颗权值线段树维护它到根的路径的区间K大值.
然后用主席树维护.
树剖求lca.
*/
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+5,M=N*20;
struct edge{int v,next;}e[N<<1];int tot,head[N];
int n,m,sz,a[N],s[N],son[N],top[N],siz[N],fa[N],dep[N];
int root[N],sum[M],ls[M],rs[M];
int ans;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void add(int x,int y){
    e[++tot].v=y;e[tot].next=head[x];head[x]=tot;
    e[++tot].v=x;e[tot].next=head[y];head[y]=tot;
}
//=========================================预处理 
void insert(int &k,int last,int l,int r,int p){
    k=++sz;
    sum[k]=sum[last]+1;
    if(l==r) return ;
    ls[k]=ls[last];
    rs[k]=rs[last];
    int mid=l+r>>1;
    if(p<=mid) insert(ls[k],ls[last],l,mid,p);
    else insert(rs[k],rs[last],mid+1,r,p);
}
int query(int l,int r,int x1,int x2,int x3,int x4,int K){
    if(l==r) return l;
    int mid=l+r>>1;
    int cnt=sum[ls[x1]]+sum[ls[x2]]-sum[ls[x3]]-sum[ls[x4]];
    if(K<=cnt) return query(l,mid,ls[x1],ls[x2],ls[x3],ls[x4],K);
    else return query(mid+1,r,rs[x1],rs[x2],rs[x3],rs[x4],K-cnt);
}
//=========================================主席树 
void dfs(int x,int f,int de){
    fa[x]=f;dep[x]=de;siz[x]=1;
    int p=lower_bound(s+1,s+n+1,a[x])-s;
    insert(root[x],root[f],1,n,p);
    for(int i=head[x];i;i=e[i].next){
        if(e[i].v!=f){
            dfs(e[i].v,x,de+1);
            siz[x]+=siz[e[i].v];
            if(siz[son[x]]<siz[e[i].v]) son[x]=e[i].v;
        }
    }
}
void getpos(int x,int tp){
    top[x]=tp;//pos[x]=++dfs_cnt;
    if(!son[x]) return ;
    getpos(son[x],tp);
    for(int i=head[x];i;i=e[i].next){
        if(e[i].v!=fa[x]&&e[i].v!=son[x]){
            getpos(e[i].v,e[i].v);
        }
    }
}
inline int lca(int x,int y){
    fa[1]=1;//求lca,fa[1]必须=1,否则就GG了 
    for(;top[x]!=top[y];x=fa[top[x]]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
    }
    fa[1]=0;//当anc=1时,防止query(...root[anc],root[fa[anc]])出问题 
    return dep[x]<dep[y]?x:y;
}
//=========================================树链剖分 
void Q_ans(int x,int y,int K){
    int anc=lca(x,y);//类比区间[l,r] 
    ans=query(1,n,root[x],root[y],root[anc],root[fa[anc]],K);
    printf("%d",ans=s[ans]);
}
int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++) s[i]=a[i]=read();
    for(int i=1,x,y;i<n;i++) x=read(),y=read(),add(x,y);
    sort(s+1,s+n+1);
    dfs(1,0,1);getpos(1,1);
    for(int i=1,x,y,z;i<=m;i++){
        x=read()^ans;y=read();z=read();
        Q_ans(x,y,z);
        if(i!=m) printf("\n");
    }
    return 0;
}

 

posted @ 2017-02-24 17:36  神犇(shenben)  阅读(264)  评论(1编辑  收藏  举报