您的位置:首页 > 理论基础 > 数据结构算法

COJ1013 WZJ的数据结构(十三)

2015-09-22 13:15 471 查看
WZJ的数据结构(十三)
难度级别:D; 运行时间限制:1000ms; 运行空间限制:262144KB; 代码长度限制:2000000B
试题描述
给你一棵N个节点的有根树(根节点为1),每个节点有权值Vi。请回答Q个问题:

每次给你两个正整数x、k,请回答以x为根的子树(包括x节点)中第k小的权值是多少(若不存在第k小数,输出-1)?

输入
第一行为两个正整数N,Q。
接下来N-1行每行两个正整数ui、vi,表示有条从ui向vi的树边。
第N+1行为N个正整数Vi。
最后Q行每行两个正整数x、k。

输出

对于每次询问输出答案,若不存在第k小数,输出-1。

输入示例

6 12
1 2
1 3
2 4
3 6
3 5
1 2 1 3 2 1
1 5
2 2
3 4
1 1
1 2
1 3
1 4
1 6
3 3
3 2
5 1
6 1

输出示例

2
3
-1
1
1
1
2
3
2
1
2
1

其他说明

1<=N,M,Vi<=100000
1<=x,k<=N

新学了线段树的合并,来try一发。

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()
{
char ch=getchar();int sig=1,x=0;
while(!isdigit(ch)) {if(ch=='-') sig=-1;ch=getchar();}
while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*sig;
}
const int maxn=100010;
const int maxnode=20000010;
int s[maxnode],ls[maxnode],rs[maxnode],ToT;
void update(int& y,int x,int l,int r,int pos)
{
s[y=++ToT]=s[x]+1;if(l==r) return;
ls[y]=ls[x];rs[y]=rs[x];int mid=l+r>>1;
if(pos<=mid) update(ls[y],ls[x],l,mid,pos);
else update(rs[y],rs[x],mid+1,r,pos);
}
int query(int x,int y,int l,int r,int k)
{
if(l==r) return l;
int mid=l+r>>1;
if(s[ls[y]]-s[ls[x]]>=k) return query(ls[x],ls[y],l,mid,k);
return query(rs[x],rs[y],mid+1,r,k-s[ls[y]]+s[ls[x]]);
}
int to[maxn*2],next[maxn*2],first[maxn],e;
void AddEdge(int a,int b)
{
to[++e]=b;next[e]=first[a];first[a]=e;
to[++e]=a;next[e]=first[b];first[b]=e;
}
int L[maxn],R[maxn],v[maxn],root[maxn],pos[maxn],ts,siz[maxn];
void dfs(int x,int fa)
{
L[x]=++ts;pos[ts]=x;siz[x]=1;
for(int i=first[x];i;i=next[i]) if(fa!=to[i]) dfs(to[i],x),siz[x]+=siz[to[i]];
R[x]=ts;
}
int main()
{
int n=read(),q=read(),x,k;
for(int i=1;i<n;i++) AddEdge(read(),read());
for(int i=1;i<=n;i++) v[i]=read();
dfs(1,0);
for(int i=1;i<=n;i++) update(root[i],root[i-1],1,n,v[pos[i]]);
while(q--)
{
x=read();k=read();
if(siz[x]>=k) printf("%d\n",query(root[L[x]-1],root[R[x]],1,n,k));
else puts("-1");
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: