P2633 Count on a tree
题目描述
给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
输入格式
第一行两个整数N,M。
第二行有N个整数,其中第i个整数表示点i的权值。
后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
最后M行每行两个整数(u,v,k),表示一组询问。
输出格式
M行,表示每个询问的答案。
输入输出样例
输入 #1
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
输出 #1
2 8 9 105 7
说明/提示
HINT:
N,M<=100000
暴力自重。。。
来源:bzoj2588 Spoj10628.
本题数据为洛谷自造数据,使用CYaRon耗时5分钟完成数据制作。
主席树乱搞+lca
#include<bits/stdc++.h> using namespace std; const int maxn = 100010; int n,m,root[maxn],size,head[maxn],lastans,f[maxn][20],dep[maxn],cnt,rank[maxn]; struct hash{ int val,id; }point[maxn]; struct Tree{ int ls,rs,sum; }tree[maxn*40]; bool cmp(const hash& a,const hash& b){ return a.val<b.val; } struct edge{ int v,nex; }e[maxn<<1]; void adde(int u,int v){ e[size].v=v;e[size].nex=head[u];head[u]=size++; } void updata(int &rt,int l,int r,int v){ tree[++cnt]=tree[rt]; rt=cnt; tree[rt].sum++; if(l==r) return; int mid=(l+r)>>1; if(mid>=v) updata(tree[rt].ls,l,mid,v); else updata(tree[rt].rs,mid+1,r,v); } void dfs(int u,int fa){ root[u]=root[fa]; updata(root[u],1,n,rank[u]); f[u][0]=fa; dep[u]=dep[fa]+1; for(int i=1;i<=18;i++) f[u][i]=f[f[u][i-1]][i-1]; for(int i=head[u];~i;i=e[i].nex){ int v=e[i].v; if(v==fa) continue; dfs(v,u); } } int query(int i,int j,int lca,int lcaf,int l,int r,int k){ if(l==r) return l; int d = tree[tree[i].ls].sum+tree[tree[j].ls].sum-tree[tree[lca].ls].sum-tree[tree[lcaf].ls].sum; int mid=(l+r)>>1; if(d>=k) return query(tree[i].ls,tree[j].ls,tree[lca].ls,tree[lcaf].ls,l,mid,k); else return query(tree[i].rs,tree[j].rs,tree[lca].rs,tree[lcaf].rs,mid+1,r,k-d); } int Lca(int u,int v){ if(dep[u]<dep[v]) swap(u,v); for(int i=18;i>=0;i--) if(dep[f[u][i]]>=dep[v]) u=f[u][i]; if(u==v) return v; for(int i=18;i>=0;i--)if(f[u][i]!=f[v][i]){ u=f[u][i];v=f[v][i]; } return f[u][0]; } int query_(int u,int v,int k){ int lca=Lca(u,v); return point[query(root[u],root[v],root[lca],root[f[lca][0]],1,n,k)].val; } int main(){ memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&point[i].val),point[i].id=i; sort(point+1,point+1+n,cmp); for(int i=1;i<=n;i++) rank[point[i].id]=i; for(int i=1;i<n;i++){ int u,v;scanf("%d%d",&u,&v); adde(u,v);adde(v,u); } dfs(1,0); for(int i=1;i<=m;i++){ int u,v,k; scanf("%d%d%d",&u,&v,&k); lastans=query_(u^lastans,v,k); printf("%d\n",lastans); } return 0; }