BZOJ 2588: Spoj 10628. Count on a tree
2588: Spoj 10628. Count on a tree
Time Limit: 12 Sec Memory Limit: 128 MBSubmit: 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
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
分析:
树上的主席树,我们对于每一个节点维护一个当前结点到根节点的路径上的权值线段树,然后查询的时候对于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