您的位置:首页 > 其它

Count on a tree

2017-02-09 20:30 148 查看

bzoj 2588: Spoj 10628. Count on a tree

http://www.lydsy.com/JudgeOnline/problem.php?id=2588

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

鸣谢seter

数据结构:主席树

辅助算法:LCA

以点的dfs序为下标,以点权为区间建立主席树

以前做过的主席树在序列上,所以是以前一个节点的线段树为基准建立的

这里在树上,所以可以考虑以根为基准建立线段树

u,v间增加的点数=cnt[u]+cnt[v]-cnt[LCA(u,v)]-cnt[father[LCA(u,v)]]

#include<cstdio>
#include<algorithm>
#define N 100001
using namespace std;
struct count
{
private:
struct node{int l,r,cnt;}tr[N*20];
struct data {int to,next;}e[N*2];
int n,m,a
,head
,edge_cnt;
int dep
,son
,f
,bl
,sz;
int root
,cntt,hash
,hash_tot;
int last;
public:
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
return x*f;
}
inline void add(int u,int v)
{
e[++edge_cnt].to=v;e[edge_cnt].next=head[u];head[u]=edge_cnt;
e[++edge_cnt].to=u;e[edge_cnt].next=head[v];head[v]=edge_cnt;
}
void init()
{
n=read();m=read();
for(int i=1;i<=n;i++) a[i]=read(),hash[i]=a[i];
int u,v;
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v);
}
}
inline void tree_insert(int pre,int & now,int l,int r,int k)
{
tr[now=++cntt].cnt=tr[pre].cnt+1;
if(l==r) return;
int mid=l+r>>1;
if(k<=mid)
{
tr[now].r=tr[pre].r;
tree_insert(tr[pre].l,tr[now].l,l,mid,k);
}
else
{
tr[now].l=tr[pre].l;
tree_insert(tr[pre].r,tr[now].r,mid+1,r,k);
}
}
inline void dfs1(int x,int fa)
{
son[x]++;
tree_insert(root[fa],root[x],1,hash_tot,hash[x]);
for(int i=head[x];i;i=e[i].next)
{
if(e[i].to==fa) continue;
f[e[i].to]=x;
dep[e[i].to]=dep[x]+1;
dfs1(e[i].to,x);
son[x]+=son[e[i].to];
}
}
inline void dfs2(int x,int chain)//给重链编号
{
bl[x]=chain;
int m=0;
for(int i=head[x];i;i=e[i].next)
{
if(e[i].to==f[x]) continue;
if(son[e[i].to]>son[m]) m=e[i].to;
}
if(!m) return;
dfs2(m,chain);
for(int i=head[x];i;i=e[i].next)
{
if(e[i].to==f[x]||e[i].to==m) continue;
dfs2(e[i].to,e[i].to);
}
}
inline int getlca(int u,int v)//求lca,本函数+上面2个函数为树链剖分求LCA
{
while(bl[u]!=bl[v])
{
if(dep[bl[u]]<dep[bl[v]]) swap(u,v);
u=f[bl[u]];
}
if(dep[u]<dep[v]) return u;
return v;
}
void discrete()
{
sort(a+1,a+n+1);
hash_tot=unique(a+1,a+n+1)-(a+1);
for(int i=1;i<=n;i++) hash[i]=lower_bound(a+1,a+hash_tot+1,hash[i])-a;
}
inline int tree_query(int x,int y,int lca,int fa_lca,int l,int r,int k)
{
if(l==r) return a[l];
int mid=l+r>>1,tmp=tr[tr[x].l].cnt+tr[tr[y].l].cnt-tr[tr[lca].l].cnt-tr[tr[fa_lca].l].cnt;
if(k<=tmp) tree_query(tr[x].l,tr[y].l,tr[lca].l,tr[fa_lca].l,l,mid,k);
else tree_query(tr[x].r,tr[y].r,tr[lca].r,tr[fa_lca].r,mid+1,r,k-tmp);
}
void init2()
{
int u,v,k;
for(int i=1;i<=m;i++)
{
u=read();v=read();k=read();
u^=last;
int lca=getlca(u,v);
last=tree_query(root[u],root[v],root[lca],root[f[lca]],1,hash_tot,k);
if(i!=m )printf("%d\n",last);
else printf("%d",last);
}
}
void work()
{
init();
discrete();
dfs1(1,0);
dfs2(1,1);
init2();
}

}a;
int main()
{
a.work();
}


初做犯了一个很蠢的错误:最后一行不输出换行,楞是没看见

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