BZOJ2588:LCA+主席树来实现树上两点之间第K大点权查询

对于每个节点维护这个节点到根的权值线段树

对于每个询问(x,y),这条路径上的线段树

tree[x]+tree[y]-tree[lca(x,y)]-tree[fa[lca(x,y)]]

  1 #include<cstdio>
  2 #include<algorithm>
  3 using namespace std;
  4 const int maxn=100005;
  5 const int maxm=2000005;
  6 int n,m,tot,cnt,ind,sz,last;
  7 int tmp[maxn],hash[maxn],g[maxn],v[maxn];
  8 int num[maxn],pos[maxn],deep[maxn];
  9 int sum[maxm],lch[maxm],rch[maxm];
 10 int root[maxn];
 11 int fa[maxn][17];
 12 struct Edge
 13 {
 14     int t,next;
 15 }e[2*maxn];
 16 inline long long read()
 17 {
 18     long long x=0,f=1;char ch=getchar();
 19     while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
 20     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
 21     return x*f;
 22 }
 23 //二分查找离散化之后的x的下标 
 24 int find(int x)
 25 {
 26     int l=1,r=tot;
 27     while(l<=r)
 28     {
 29         int mid=(l+r)>>1;
 30         if(hash[mid]<x) l=mid+1;
 31         else if(hash[mid]==x) return mid;
 32         else r=mid-1;
 33     }
 34     return l;
 35 }
 36 void insert(int u,int v)
 37 {
 38     cnt++;
 39     e[cnt].t=v;e[cnt].next=g[u];g[u]=cnt;
 40     cnt++;
 41     e[cnt].t=u;e[cnt].next=g[v];g[v]=cnt;
 42 }
 43 void dfs(int x)
 44 {
 45     ind++;num[ind]=x;pos[x]=ind;
 46     for(int i=1;i<=16;i++)
 47         if((1<<i)<=deep[x]) fa[x][i]=fa[fa[x][i-1]][i-1];
 48         else break;
 49     for(int tmp=g[x];tmp;tmp=e[tmp].next)
 50     {
 51         if(fa[x][0]!=e[tmp].t)
 52         {
 53             deep[e[tmp].t]=deep[x]+1;
 54             fa[e[tmp].t][0]=x;
 55             dfs(e[tmp].t);
 56         }
 57     }
 58 }
 59 void update(int l,int r,int x,int &y,int num)
 60 {
 61     y=++sz;
 62     sum[y]=sum[x]+1;
 63     if(l==r) return;
 64     lch[y]=lch[x];rch[y]=rch[x];
 65     int mid=(l+r)>>1;
 66     if(num<=mid)
 67         update(l,mid,lch[x],lch[y],num);
 68     else update(mid+1,r,rch[x],rch[y],num);
 69 } 
 70 int lca(int x,int y)
 71 {
 72     if(deep[x]<deep[y]) swap(x,y);
 73     int t=deep[x]-deep[y];
 74     for(int i=0;i<=16;i++)
 75         if((1<<i)&t) x=fa[x][i];
 76     for(int i=16;i>=0;i--)
 77         if(fa[x][i]!=fa[y][i])
 78             x=fa[x][i],y=fa[y][i];
 79     if(x==y) return x;
 80     return fa[x][0];
 81 }
 82 int query(int x,int y,int rk)
 83 {
 84     int a=x,b=y,c=lca(x,y),d=fa[c][0];
 85     a=root[pos[a]],b=root[pos[b]],c=root[pos[c]],d=root[pos[d]];
 86     int l=1,r=tot;
 87     while(l<r)
 88     {
 89         int mid=(l+r)>>1;
 90         int tmp=sum[lch[a]]+sum[lch[b]]-sum[lch[c]]-sum[lch[d]];
 91         if(tmp>=rk) r=mid,a=lch[a],b=lch[b],c=lch[c],d=lch[d];
 92         else rk-=tmp,l=mid+1,a=rch[a],b=rch[b],c=rch[c],d=rch[d];
 93     }
 94     return hash[l];
 95 }
 96 int main()
 97 {
 98     n=read();m=read();
 99     for(int i=1;i<=n;i++)
100         v[i]=read(),tmp[i]=v[i];
101     sort(tmp+1,tmp+n+1);  //点权排序
102     hash[++tot]=tmp[1];
103     for(int i=2;i<=n;i++)
104         if(tmp[i]!=tmp[i-1])
105             hash[++tot]=tmp[i];
106     //离散化 
107     for(int i=1;i<=n;i++) v[i]=find(v[i]); 
108     //存位置,离散化
109     for(int i=1;i<n;i++)
110     {
111         int u,v;
112         u=read();v=read();
113         insert(u,v);
114     } 
115     dfs(1);
116     for(int i=1;i<=n;i++)
117     {
118         int t=num[i];  //树上点权
119         update(1,tot,root[pos[fa[t][0]]],root[i],v[t]);//建立主席树 
120     }
121     for(int i=1;i<=m;i++)
122     {
123         int x=read(),y=read(),rk=read();
124         x^=last;
125         last=query(x,y,rk);
126         printf("%d",last);
127         if(i!=m) printf("\n");
128     }
129     return 0;
130 }

 

posted @ 2018-09-06 17:52  静听风吟。  阅读(333)  评论(0编辑  收藏  举报