BZOJ 2588: Spoj 10628. Count on a tree

2588: Spoj 10628. Count on a tree

Time Limit: 12 Sec  Memory Limit: 128 MB
Submit: 5620  Solved: 1336
[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

鸣谢seter

分析:

树上的主席树,我们对于每一个节点维护一个当前结点到根节点的路径上的权值线段树,然后查询的时候对于x到y的路径我们用sum[x]+sum[y]-sum[lca]-sum[fa[lca]]来查询...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;
  
const int maxn=200000+5,maxm=7000000+5;
  
int n,m,cnt,len,tot,w[maxn],hd[maxn],mp[maxn],ls[maxm],rs[maxm],to[maxn],fa[maxn][25],nxt[maxn],sum[maxm],dep[maxn],root[maxn];
  
inline void add(int x,int y){
    to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
}
  
inline int find(int x){
    int l=1,r=len,ans;
    while(l<=r){
        int mid=(l+r)>>1;
        if(mp[mid]>=x)
            ans=mid,r=mid-1;
        else
            l=mid+1;
    }
    return ans;
}
  
inline void change(int l,int r,int x,int &y,int val){
    y=++tot,sum[y]=sum[x]+1;
    if(l==r)
        return;
    int mid=(l+r)>>1;ls[y]=ls[x],rs[y]=rs[x];
    if(val<=mid)
        change(l,mid,ls[x],ls[y],val);
    else
        change(mid+1,r,rs[x],rs[y],val);
}
  
inline void dfs(int rt,int f){
    change(1,len,rt==1?root[0]:root[fa[rt][0]],root[rt],find(w[rt]));
    for(int i=hd[rt];i!=-1;i=nxt[i])
        if(to[i]!=f)
            dep[to[i]]=dep[rt]+1,fa[to[i]][0]=rt,dfs(to[i],rt);
}
  
inline void init(void){
    for(int j=1;j<=20;j++)
        for(int i=1;i<=n;i++)
            fa[i][j]=fa[fa[i][j-1]][j-1];
}
  
inline int LCA(int x,int y){
    if(dep[x]<dep[y])
        swap(x,y);
    int d=dep[x]-dep[y];
    for(int i=0;i<=20;i++)
        if((d>>i)&1)
            x=fa[x][i];
    if(x==y)
        return x;
    for(int i=20;i>=0;i--)
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
  
inline int query(int l,int r,int x,int y,int lca,int flca,int num){
    if(l==r)
        return l;
    int mid=(l+r)>>1;
    if(sum[ls[x]]+sum[ls[y]]-sum[ls[lca]]-sum[ls[flca]]>=num)
        return query(l,mid,ls[x],ls[y],ls[lca],ls[flca],num);
    else
        return query(mid+1,r,rs[x],rs[y],rs[lca],rs[flca],num-(sum[ls[x]]+sum[ls[y]]-sum[ls[lca]]-sum[ls[flca]]));
}
  
signed main(void){
    memset(hd,-1,sizeof(hd));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&w[i]),mp[i]=w[i];
    sort(mp+1,mp+n+1),len=unique(mp+1,mp+n+1)-mp-1;
    for(int i=1,x,y;i<n;i++)
        scanf("%d%d",&x,&y),add(x,y),add(y,x);
    fa[1][0]=1;dfs(1,-1);init();int ans=0,lca;
    for(int i=1,s,x,y;i<=m;i++){
        scanf("%d%d%d",&x,&y,&s),lca=LCA(ans^x,y),printf("%d",ans=mp[query(1,len,root[ans^x],root[y],root[lca],root[lca==1?0:fa[lca][0]],s)]);
        if(i<m)
            puts("");
    }
    return 0;
}

  


By NeighThorn

posted @ 2017-02-13 10:17  NeighThorn  阅读(97)  评论(0编辑  收藏  举报