隐藏页面特效

2588: Spoj 10628. Count on a tree

2588: Spoj 10628. Count on a tree

Time Limit: 12 Sec  Memory Limit: 128 MB
Submit: 5766  Solved: 1374
[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

Sample Output

2
8
9
105
7

HINT

 




HINT:

N,M<=100000

暴力自重。。。

 

Source

/* 树上第K大. 对于每一个节点以key(权值)为下标 用一颗权值线段树维护它到根的路径的区间K大值. 然后用主席树维护. 树剖求lca. */ #include<cstdio> #include<algorithm> using namespace std; const int N=1e5+5,M=N*20; struct edge{int v,next;}e[N<<1];int tot,head[N]; int n,m,sz,a[N],s[N],son[N],top[N],siz[N],fa[N],dep[N]; int root[N],sum[M],ls[M],rs[M]; int ans; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void add(int x,int y){ e[++tot].v=y;e[tot].next=head[x];head[x]=tot; e[++tot].v=x;e[tot].next=head[y];head[y]=tot; } //=========================================预处理 void insert(int &k,int last,int l,int r,int p){ k=++sz; sum[k]=sum[last]+1; if(l==r) return ; ls[k]=ls[last]; rs[k]=rs[last]; int mid=l+r>>1; if(p<=mid) insert(ls[k],ls[last],l,mid,p); else insert(rs[k],rs[last],mid+1,r,p); } int query(int l,int r,int x1,int x2,int x3,int x4,int K){ if(l==r) return l; int mid=l+r>>1; int cnt=sum[ls[x1]]+sum[ls[x2]]-sum[ls[x3]]-sum[ls[x4]]; if(K<=cnt) return query(l,mid,ls[x1],ls[x2],ls[x3],ls[x4],K); else return query(mid+1,r,rs[x1],rs[x2],rs[x3],rs[x4],K-cnt); } //=========================================主席树 void dfs(int x,int f,int de){ fa[x]=f;dep[x]=de;siz[x]=1; int p=lower_bound(s+1,s+n+1,a[x])-s; insert(root[x],root[f],1,n,p); for(int i=head[x];i;i=e[i].next){ if(e[i].v!=f){ dfs(e[i].v,x,de+1); siz[x]+=siz[e[i].v]; if(siz[son[x]]<siz[e[i].v]) son[x]=e[i].v; } } } void getpos(int x,int tp){ top[x]=tp;//pos[x]=++dfs_cnt; if(!son[x]) return ; getpos(son[x],tp); for(int i=head[x];i;i=e[i].next){ if(e[i].v!=fa[x]&&e[i].v!=son[x]){ getpos(e[i].v,e[i].v); } } } inline int lca(int x,int y){ fa[1]=1;//求lca,fa[1]必须=1,否则就GG了 for(;top[x]!=top[y];x=fa[top[x]]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); } fa[1]=0;//当anc=1时,防止query(...root[anc],root[fa[anc]])出问题 return dep[x]<dep[y]?x:y; } //=========================================树链剖分 void Q_ans(int x,int y,int K){ int anc=lca(x,y);//类比区间[l,r] ans=query(1,n,root[x],root[y],root[anc],root[fa[anc]],K); printf("%d",ans=s[ans]); } int main(){ n=read();m=read(); for(int i=1;i<=n;i++) s[i]=a[i]=read(); for(int i=1,x,y;i<n;i++) x=read(),y=read(),add(x,y); sort(s+1,s+n+1); dfs(1,0,1);getpos(1,1); for(int i=1,x,y,z;i<=m;i++){ x=read()^ans;y=read();z=read(); Q_ans(x,y,z); if(i!=m) printf("\n"); } return 0; }

 


__EOF__

本文作者shenben
本文链接https://www.cnblogs.com/shenben/p/6439513.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   神犇(shenben)  阅读(267)  评论(1编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示