bzoj 2588(树链剖分+主席树)

7 篇文章 0 订阅
5 篇文章 0 订阅

2588: Spoj 10628. Count on a tree

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

暴力自重。。。


解题思路:复习一下树链剖分和主席树。


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,len,sug,size_z,tail,ans;
int zhi[110000];
struct ss
 {
  int zhi,dui;
 }qg[110000];
struct sg
 {
  int x,y;
 }q[110000];
int to[210000],next[210000],h[110000],deep[110000],son[110000],size[110000],fa[110000]; 
int dui[210000],messi[210000],hash[210000],top[210000],root[110000];
int sum[2200000],l[2200000],r[2200000]; 
 
void insert(int x,int y){++len; to[len]=y; next[len]=h[x]; h[x]=len;}
inline int read()
{
char y;int x=0,f=1; y=getchar();
while (y<'0' || y>'9') {if (y=='-') f=-1; y=getchar();}
while (y>='0' && y<='9') {x=x*10+int (y)-48; y=getchar();}
return x*f;
}
bool cmp(ss x,ss y) {return x.zhi<y.zhi;}


void dfs1(int now,int f,int lg)
 {
  deep[now]=lg;
  int u=h[now]; size[now]=1; son[now]=0; fa[now]=f; 
  while (u!=0)
  {
  if (to[u]!=f)
  {
  dfs1(to[u],now,lg+1);
  size[now]+=size[to[u]];
  if (size[to[u]]>size[son[now]]) son[now]=to[u];
}
u=next[u];
 }
 }


void dfs2(int now,int f,int tp)
 {
  ++sug; dui[now]=sug; messi[sug]=zhi[now];
  if (tp!=-1) top[now]=tp; else top[now]=now;
  if (son[now]==0) return; dfs2(son[now],now,top[now]);
  int u=h[now];
  while (u!=0)
  {
  if (to[u]!=f && to[u]!=son[now])
  {
  dfs2(to[u],now,-1);
}
u=next[u];
 }
 }


void build(int x,int &y,int lg,int rg,int zhi)
 {
  ++size_z; y=size_z; sum[size_z]=sum[x]+1;
  if (lg==rg) return;
  int mid=(lg+rg)/2;
  if (zhi<=mid)
  {
  l[y]=l[x]; r[y]=r[x];
  build(l[x],l[y],lg,mid,zhi);
 }else
  {
  l[y]=l[x]; r[y]=r[x];
  build(r[x],r[y],mid+1,rg,zhi);
  }
 }




int query(int lg,int rg,int k)
 {
  if (lg==rg) return lg;
  int sa=0;
  for (int i=1;i<=tail;++i)
  {
  sa=sa+sum[l[q[i].y]]-sum[l[q[i].x]];
}
int mid=(lg+rg)/2;
if (sa>=k)
{
for (int i=1;i<=tail;++i) {q[i].y=l[q[i].y]; q[i].x=l[q[i].x];}
return query(lg,mid,k);
}else
 {
  for (int i=1;i<=tail;++i) {q[i].y=r[q[i].y]; q[i].x=r[q[i].x];}
return query(mid+1,rg,k-sa);
 }

 }


int main()
{
n=read(); m=read();
for (int i=1;i<=n;++i)
{
 qg[i].zhi=read(); qg[i].dui=i; 
}
    sort(qg+1,qg+n+1,cmp);
    int op=0;
    for (int i=1;i<=n;++i)
     {
      if (qg[i].zhi!=qg[i-1].zhi){op+=1;} hash[op]=qg[i].zhi;
zhi[qg[i].dui]=op; 
}
for (int i=1;i<=n-1;++i)
{
int x=read(); int y=read(); insert(x,y); insert(y,x);
}
    dfs1(1,0,1); sug=0;
    dfs2(1,0,-1); size_z=0;
    for (int i=1;i<=n;++i)
     {
      build(root[i-1],root[i],1,op,messi[i]);
}
    ans=0; 
    for (int i=1;i<=m;++i)
     {
      int u,v,k; u=read(); v=read(); k=read();
      u=ans^u;
      tail=0;  
while (top[u]!=top[v])
{
if (deep[top[u]]>=deep[top[v]])
{
  ++tail; q[tail].x=root[dui[top[u]]-1]; q[tail].y=root[dui[u]]; u=fa[top[u]];
}else
 {
  ++tail; q[tail].x=root[dui[top[v]]-1]; q[tail].y=root[dui[v]]; v=fa[top[v]];
  }
}  
if (deep[u]>deep[v]) swap(u,v); ++tail; q[tail].x=root[dui[u]-1]; q[tail].y=root[dui[v]];
ans=hash[query(1,op,k)];
if (i<=m)printf("%d\n",ans);else printf("%d",ans);
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值