【树上主席树】BZOJ2588-Count on a tree

【题目大意】

给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
 
【思路】
这道题迷之好写,因为思路条理太清晰了!
我们每个点就是一棵线段树,维护它到根的每个数字的个数,但是这样会MLE所以自然而然地用主席树来维护。
u->v路径上每种的个数就等于sum[u]-sum[lca(u,v)]+sum[v]-sum[fa[lca(u,v)]]。
写起来特别爽。
然而我RE了一个上午。接着突然发现题意“(u,v)表示u到v有一条边)它居然是无向的??天真地以为有向u->v,调出了一开始的程序,默默地改掉,默默地AC...
还我两小时的人生!!!!
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<vector>
  6 #define lson l,m
  7 #define rson m+1,r
  8 using namespace std;
  9 const int MAXN=100000+500;
 10 const int DEG=20;
 11 int w[MAXN];
 12 vector<int> E[MAXN];
 13 int d,hash[MAXN];
 14 int T[MAXN],tot,sum[MAXN<<5],L[MAXN<<5],R[MAXN<<5];
 15 int anc[MAXN][DEG],dep[MAXN];
 16 int n,m;
 17 
 18 /*Chairman Tree*/
 19 int build(int l,int r)
 20 {
 21     int rt=++tot;
 22     sum[rt]=0;
 23     if (l!=r)
 24     {
 25         int m=(l+r)>>1;
 26         L[rt]=build(lson);
 27         R[rt]=build(rson); 
 28     }
 29     return rt;
 30 }
 31 
 32 int update(int pre,int l,int r,int x)
 33 {
 34     int rt=++tot;
 35     L[rt]=L[pre],R[rt]=R[pre];
 36     sum[rt]=sum[pre]+1;
 37     if (l!=r)
 38     {
 39         int m=(l+r)>>1;
 40         if (x<=m) L[rt]=update(L[pre],lson,x);
 41             else R[rt]=update(R[pre],rson,x);
 42     }
 43     return rt;
 44 }
 45 
 46 int query(int u,int v,int lca,int lcafa,int l,int r,int k)
 47 {
 48     if (l==r) return l;
 49     int num=(sum[L[u]]-sum[L[lca]]+sum[L[v]]-sum[L[lcafa]]);
 50     int m=(l+r)>>1;
 51     if (num>=k) return query(L[u],L[v],L[lca],L[lcafa],lson,k);
 52         else return query(R[u],R[v],R[lca],R[lcafa],rson,k-num);
 53 }
 54 
 55 /*LCA*/
 56 void getanc()
 57 {
 58     for (int i=1;i<DEG;i++)
 59         for (int j=1;j<=n;j++)
 60             anc[j][i]=anc[anc[j][i-1]][i-1];
 61 }
 62 
 63 int swim(int x,int H)
 64 {
 65     for (int i=0;H>0;i++)
 66     {
 67         if (H&1) x=anc[x][i];
 68         H>>=1;
 69     }
 70     return x;
 71 }
 72 
 73 int LCA(int u,int v)
 74 {
 75     if (dep[u]<dep[v]) swap(u,v);
 76     u=swim(u,dep[u]-dep[v]);
 77     if (u==v) return u;
 78     for (int i=DEG-1;i>=0;i--)
 79     {
 80         if (anc[u][i]!=anc[v][i])
 81         {
 82             u=anc[u][i];
 83             v=anc[v][i];
 84         }
 85     }
 86     return anc[u][0];
 87 }
 88  
 89 /*main*/
 90 void dfs(int u,int pa,int depth)
 91 { 
 92     anc[u][0]=pa;
 93     dep[u]=depth;
 94     int x=lower_bound(hash+1,hash+d+1,w[u])-hash;
 95     T[u]=update(T[pa],1,d,x);
 96     for (int i=0;i<E[u].size();i++)
 97         if (E[u][i]!=pa) dfs(E[u][i],u,depth+1);
 98 }
 99 
100 void init()
101 {
102     scanf("%d%d",&n,&m);
103     for (int i=1;i<=n;i++) scanf("%d",&w[i]),hash[i]=w[i];
104     sort(hash+1,hash+n+1);
105     d=unique(hash+1,hash+n+1)-(hash+1);
106     
107     for (int i=1;i<n;i++)
108     {
109         int u,v;
110         scanf("%d%d",&u,&v);
111         E[u].push_back(v);
112         E[v].push_back(u);
113     }
114 
115     
116     tot=0;
117     T[1]=build(1,d);//对于根先建立主席树
118 }
119 
120 void solve()
121 {
122     getanc();
123     int preans=0;
124     for (int i=0;i<m;i++)
125     {
126         int u,v,k;
127         scanf("%d%d%d",&u,&v,&k);
128         u=u^preans;
129         int lca=LCA(u,v);
130         int ans=query(T[u],T[v],T[lca],T[anc[lca][0]],1,d,k);
131         printf("%d",hash[ans]);
132         if (i!=m-1) printf("\n");
133         preans=hash[ans];
134     }
135 }
136 
137 int main()
138 {
139     init();
140     dfs(1,0,1);
141     solve();
142     return 0;
143 }

 

posted @ 2016-08-15 12:10  iiyiyi  阅读(169)  评论(0编辑  收藏  举报