您的位置:首页 > 其它

Bzoj 2588: Spoj 10628. Count on a tree 主席树,离散化,可持久,倍增LCA

2016-03-14 19:51 465 查看

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

2588: Spoj 10628. Count on a tree

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

鸣谢seter

题解:

在树上建主席树,记得最后一行后没有空格,否则PE.

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
struct node
{
int begin,end,next;
}edge[MAXN*2];
struct NODE
{
int left,right;
}tree[MAXN*20];
int cnt,Head[MAXN],n,SIZE,value[MAXN],pos[MAXN],deep[MAXN],P[MAXN][17],sum[MAXN*20],a[MAXN],val[MAXN],root[MAXN],tot;
bool vis[MAXN];
void addedge(int bb,int ee)
{
edge[++cnt].begin=bb;edge[cnt].end=ee;edge[cnt].next=Head[bb];Head[bb]=cnt;
}
void addedge1(int bb,int ee)
{
addedge(bb,ee);addedge(ee,bb);
}
int read()
{
int s=0,fh=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();}
return s*fh;
}
void dfs1(int u)
{
int i,v;
SIZE++;value[SIZE]=u;pos[u]=SIZE;
vis[u]=true;
for(i=Head[u];i!=-1;i=edge[i].next)
{
v=edge[i].end;
if(vis[v]==false)
{
deep[v]=deep[u]+1;
P[v][0]=u;
dfs1(v);
}
}
}
void Ycl()
{
int i,j;
for(j=1;(1<<j)<=n;j++)
{
for(i=1;i<=n;i++)
{
if(P[i][j-1]!=-1)P[i][j]=P[P[i][j-1]][j-1];
}
}
}
int LCA(int x,int y)
{
int i,j;
if(deep[x]<deep[y])swap(x,y);
for(i=0;(1<<i)<=deep[x];i++);i--;
for(j=i;j>=0;j--)if(deep[x]-(1<<j)>=deep[y])x=P[x][j];
if(x==y)return x;
for(j=i;j>=0;j--)
{
if(P[x][j]!=-1&&P[x][j]!=P[y][j])
{
x=P[x][j];
y=P[y][j];
}
}
return P[x][0];
}
void Update(int x,int &y,int l,int r,int k)
{
y=++SIZE;
sum[y]=sum[x]+1;
if(l==r)return;
tree[y].left=tree[x].left;tree[y].right=tree[x].right;
int mid=(l+r)/2;
if(k<=mid)Update(tree[x].left,tree[y].left,l,mid,k);
else Update(tree[x].right,tree[y].right,mid+1,r,k);
}
int query(int l,int r,int A,int B,int C,int D,int k)
{
if(l==r)return l;
int mid=(l+r)/2,tmp=sum[tree[A].left]+sum[tree[B].left]-sum[tree[C].left]-sum[tree[D].left];
if(k<=tmp)return query(l,mid,tree[A].left,tree[B].left,tree[C].left,tree[D].left,k);
else return query(mid+1,r,tree[A].right,tree[B].right,tree[C].right,tree[D].right,k-tmp);
}
int Query(int A,int B,int k)
{
int C=LCA(A,B),D=P[C][0];
A=root[pos[A]];B=root[pos[B]];C=root[pos[C]];D=root[pos[D]];
return query(1,tot,A,B,C,D,k);
}
int main()
{
int m,i,bb,ee,k,k1,lastans,U,V,K;
n=read();m=read();
for(i=1;i<=n;i++)a[i]=val[i]=read();
sort(val+1,val+n+1);
tot=unique(val+1,val+n+1)-(val+1);
memset(Head,-1,sizeof(Head));cnt=1;
for(i=1;i<n;i++)
{
bb=read();ee=read();
addedge1(bb,ee);
}
memset(P,-1,sizeof(P));SIZE=0;
memset(value,0,sizeof(value));//树上每个编号的实际的点.
memset(pos,0,sizeof(pos));//每个点在树上的编号.
dfs1(1);Ycl();
memset(root,0,sizeof(root));
SIZE=0;
for(i=1;i<=n;i++)//i为树上的节点.(即i为每个点在树上的编号.)
{
k=value[i];
k1=lower_bound(val+1,val+tot+1,a[k])-val;
Update(root[pos[P[k][0]]],root[i],1,tot,k1);
}
lastans=0;
for(i=1;i<=m;i++)
{
U=read();V=read();K=read();
U^=lastans;
lastans=val[Query(U,V,K)];
printf("%d",lastans);
if(i!=m)printf("\n");
}
fclose(stdin);
fclose(stdout);
return 0;
}


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