[BZOJ2588] Count on a tree

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

思路

树链剖分+主席树,然后用一棵线段树辅助查询。

没注意判断,有一些查询集里多加了root节点;

然后R了好久;

然后,多谢大佬提醒,给区间边界加了特判,然后就能在答案错误时输出了;

然后T掉了。。。

没搞清楚主席树,主席树是对于某一个节点扩展出新树,所以树状数据也可以直接按父子关系存储;

然后用LCA get到所需的树链的数据,查询即可;

然后。。。学了一下unique()去重函数;

代码实现

 1 #include<cstdio>
 2 #include<cstring>
 3 const int maxn=1e5+10;
 4 const int inf=0x7fffffff;
 5 inline int min_(int x,int y){return x<y?x:y;}
 6 inline int max_(int x,int y){return x>y?x:y;}
 7 inline void swap_(int&x,int&y){x^=y,y^=x,x^=y;}
 8 int h[maxn],hs,et[maxn<<1],en[maxn<<1];
 9 int p[maxn],pf[maxn],pd[maxn],pt[maxn],pp[maxn],pps,psz[maxn],pws[maxn];
10 int s[maxn];
11 int rt[maxn],ts,t[maxn<<5],tl[maxn<<5],tr[maxn<<5];
12 int nrt,nts,nt[maxn<<4],ntl[maxn<<4],ntr[maxn<<4];
13 int n,m;
14 int a,b,c,ans;
15 void dfs1(int k,int f,int d){
16     pf[k]=f,pd[k]=d,psz[k]=1;
17     for(int i=h[k];i;i=en[i])
18     if(et[i]!=f){
19         dfs1(et[i],k,d+1);
20         psz[k]+=psz[et[i]];
21         if(psz[et[i]]>psz[pws[k]]) pws[k]=et[i];
22     }
23 }
24 void dfs2(int k,int t){
25     s[++pps]=p[k],pp[k]=pps,pt[k]=t;
26     if(pws[k]) dfs2(pws[k],t);
27     for(int i=h[k];i;i=en[i])
28     if(et[i]!=pf[k]&&et[i]!=pws[k])
29     dfs2(et[i],et[i]);
30 }
31 void build(int pre,int&suc,int l,int r,int v){
32     suc=++ts;
33     if(l==r){t[suc]=t[pre]+1;return;}
34     int mid=0ll+l+r>>1;
35     if(v<=mid) tr[suc]=tr[pre],build(tl[pre],tl[suc],l,mid,v);
36     else tl[suc]=tl[pre],build(tr[pre],tr[suc],mid+1,r,v);
37     t[suc]=t[tl[suc]]+t[tr[suc]];
38 }
39 void move(int pre,int suc,int&k,int l,int r){
40     if(!k) k=++nts;
41     nt[k]+=t[suc]-t[pre];
42     if(l==r) return;
43     int mid=0ll+l+r>>1;
44     if(t[tl[suc]]-t[tl[pre]]) move(tl[pre],tl[suc],ntl[k],l,mid);
45     if(t[tr[suc]]-t[tr[pre]]) move(tr[pre],tr[suc],ntr[k],mid+1,r);
46 }
47 int search(int k,int l,int r,int v){
48     if(l==r) return l;
49     int mid=0ll+l+r>>1,ls=k<<1,rs=ls|1;
50     if(v<=nt[ntl[k]]) return search(ntl[k],l,mid,v);
51     else return search(ntr[k],mid+1,r,v-nt[ntl[k]]);
52 }
53 int main(){
54     scanf("%d%d",&n,&m);
55     for(int i=1;i<=n;i++) scanf("%d",&p[i]);
56     for(int i=1;i<n;i++){
57         scanf("%d%d",&a,&b);
58         ++hs,et[hs]=b,en[hs]=h[a],h[a]=hs;
59         ++hs,et[hs]=a,en[hs]=h[b],h[b]=hs;
60     }
61     dfs1(1,1,1);
62     dfs2(1,1);
63     for(int i=1;i<=n;i++) build(rt[i-1],rt[i],1,inf,s[i]);
64     for(int i=1;i<=m;i++){
65         scanf("%d%d%d",&a,&b,&c);a^=ans;
66         while(pt[a]!=pt[b]){
67             if(pd[pt[a]]<pd[pt[b]]) swap_(a,b);
68             move(rt[pp[pt[a]]-1],rt[pp[a]],nrt,1,inf);
69             a=pf[pt[a]];
70         }
71         if(pp[a]>pp[b]) swap_(a,b);
72         move(rt[pp[a]-1],rt[pp[b]],nrt,1,inf);
73         ans=search(nrt,1,inf,c);
74         printf("%d",ans);
75         nrt=nts=0;
76         memset(nt,0,sizeof(nt));
77         memset(ntl,0,sizeof(ntl));
78         memset(ntr,0,sizeof(ntr));
79         if(i!=m) putchar('
');
80     }
81     return 0;
82 }
T掉了。
 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn=1e5+10;
 5 int n,m;
 6 int a,b,c,aa,bb,ans,inf;
 7 int h[maxn],hs,et[maxn<<1],en[maxn<<1];
 8 int p[maxn],pf[maxn][32],pd[maxn];
 9 int rt[maxn],ts,t[maxn<<5],tl[maxn<<5],tr[maxn<<5];
10 int s[maxn],hash[maxn];
11 void build(int pre,int&suc,int l,int r,int v){
12     if(!suc) suc=++ts;
13     t[suc]=t[pre]+1;
14     if(l==r) return;
15     int mid=0ll+l+r>>1;
16     if(v<=hash[mid]) tr[suc]=tr[pre],build(tl[pre],tl[suc],l,mid,v);
17     else tl[suc]=tl[pre],build(tr[pre],tr[suc],mid+1,r,v);
18 }
19 void dfs(int k,int f,int d){
20     pd[k]=d,s[d]=k;
21     build(rt[f],rt[k],1,inf,p[k]);
22     for(int i=1,j=0;d-i>0;i<<=1,j++) pf[k][j]=s[d-i];
23     for(int i=h[k];i;i=en[i])
24     if(et[i]!=f) dfs(et[i],k,d+1);
25 }
26 int search(int k1,int k2,int k3,int k4,int l,int r,int v){
27     if(l==r) return l;
28     int mid=0ll+l+r>>1,w=t[tl[k1]]+t[tl[k2]]-t[tl[k3]]-t[tl[k4]];
29     if(v<=w) return search(tl[k1],tl[k2],tl[k3],tl[k4],l,mid,v);
30     else return search(tr[k1],tr[k2],tr[k3],tr[k4],mid+1,r,v-w);
31 }
32 int main(){
33     scanf("%d%d",&n,&m);
34     for(int i=1;i<=n;i++) scanf("%d",&p[i]),hash[i]=p[i];
35     sort(hash+1,hash+n+1);
36     inf=unique(hash,hash+n+1)-hash-1;
37     for(int i=1;i<n;i++){
38         scanf("%d%d",&a,&b);
39         ++hs,et[hs]=b,en[hs]=h[a],h[a]=hs;
40         ++hs,et[hs]=a,en[hs]=h[b],h[b]=hs;
41     }
42     dfs(1,0,1);
43     while(m--){
44         scanf("%d%d%d",&a,&b,&c);
45         a^=ans,aa=a,bb=b;
46         if(a<0||a>n) return 0;
47         while(a!=b){
48             if(pd[a]==pd[b]) for(int j=0;;j++) if(pf[a][j+1]==pf[b][j+1]){a=pf[a][j],b=pf[b][j];break;}
49             if(pd[a]>pd[b]) for(int j=0;;j++) if(pd[pf[a][j+1]]<pd[b]){a=pf[a][j];break;}
50             if(pd[a]<pd[b]) for(int j=0;;j++) if(pd[pf[b][j+1]]<pd[a]){b=pf[b][j];break;}
51         }
52         ans=hash[search(rt[aa],rt[bb],rt[a],rt[pf[a][0]],1,inf,c)];
53         printf("%d",ans);
54         if(m) putchar('
');
55     }
56     return 0;
57 }

 顺便,SPOJ这道题因为太水已经被删除了。。。我好弱。

顺便,对拍用的maker. by:http://blog.csdn.net/baidu_23081367/article/details/53036792

 1     #include <cstdio>  
 2     #include <cstring>  
 3     #include <vector>  
 4     #include <ctime>  
 5     #include <iostream>  
 6     #include <cstdlib>  
 7     using namespace std;  
 8       
 9     int main()  
10     {  
11         srand(time(0));  
12         int T=1;//改数据组数  
13         while (T--)  
14         {  
15             int n = rand() % 100 + 1; //这里改树的大小  
16             int m = 100;  //修改询问次数  
17             cout<<n<<" "<<m<<endl;  
18             for (int i = 1; i <= n; ++ i)  
19                 cout << rand()%100+1<<" ";cout<<endl; //修改每个读入的数字大小  
20             for (int i = 2; i <= n; ++ i)  
21             {  
22                 int a = i, b = rand()%(i-1)+1;  
23                 cout << a <<" " << b<<endl;  
24             }  
25             while ( m -- )  
26             {  
27                 int a = rand()%n+1;  
28                 int b = rand()%n+1;  
29                 int l = abs(a-b)+1;  
30                 cout<<a<<" "<<b<<" "<<rand()%l+1<<endl;  
31             }  
32         }  
33         return 0;  
34     }  
原文地址:https://www.cnblogs.com/J-william/p/7029413.html