[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
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
8
9
105
7
HINT
HINT:
N,M<=100000
暴力自重。。。
Source
思路
树链剖分+主席树,然后用一棵线段树辅助查询。
没注意判断,有一些查询集里多加了root节点;
然后R了好久;
然后,多谢大佬提醒,给区间边界加了特判,然后就能在答案错误时输出了;
然后T掉了。。。
没搞清楚主席树,主席树是对于某一个节点扩展出新树,所以树状数据也可以直接按父子关系存储;
然后用LCA get到所需的树链的数据,查询即可;
然后。。。学了一下unique()去重函数;
代码实现
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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('\n'); 80 } 81 return 0; 82 }
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('\n'); 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 }