[BZOJ2588]Spoj 10628. Count on a tree
阿新 • • 發佈:2018-12-24
題意
給定一個有n個結點的樹,線上詢問兩個點之間路徑上第k大的點的點權是多少。
分析
其實剛開始看到這道題的想法是樹鏈剖分出log條鏈在同時在可持久化線段樹上查詢第k大。但是這樣寫起來並不優雅而且很難寫。
然後考慮每次其實相當於取出兩條點到某個祖先的鏈找第k大,所以這裡的可持久化線段樹可以不基於dfs序,而是直接用父親結點的線段樹。
然後這樣就只需要求一個lca,然後開始的時候建一棵可持久化線段樹即可。
code
//2018年06月09日 星期六 10時16分17秒
#include<bits/stdc++.h>
#define M 100005
using namespace std;
void read (int &x){
x=0; char c=getchar();
for (;c<48;c=getchar());
for (;c>47;c=getchar())x=(x<<1)+(x<<3)+(c^48);
}
struct ed{
int x,nx;
}e[M<<1];
int a[M],b[M],rt[M],fa[M],top[M],son[M],de[M],nx[M],ecnt=1,cnt[M];
void add(int x,int y){
e[ecnt]=(ed){y,nx[x]};
nx[x ]=ecnt++;
}
int ch(int l,int r,int x){
int mid;
for (;l<=r;){
mid=(l+r)>>1;
if (b[mid]==x)return mid;
if (b[mid]<x)l=mid+1;
else r=mid-1;
}
}
struct Tree{
int tot,f[M*30],rs[M*30],ls[M*30];
void build(int l,int r,int &p){
p=++tot;
if (l==r)return;
int mid=(l+r)>>1;
build(l,mid,ls[p]);
build(mid+1,r,rs[p]);
}
void build(int l,int r,int x,int lp,int &p){
p=++tot;
ls[p]=ls[lp];
rs[p]=rs[lp];
f[p]=f[lp]+1;
if (l==r){
return;
}
int mid=(l+r)>>1;
if (x<=mid)build(l,mid,x,ls[lp],ls[p]);
else build(mid+1,r,x,rs[lp],rs[p]);
}
int qu(int l,int r,int k,int p1,int p2,int p3,int p4){
if (l==r)return l;
int sum=(f[ls[p1]]+f[ls[p2]]-f[ls[p3]]-f[ls[p4]]),mid=(l+r)>>1;
if (sum>=k)return qu(l,mid,k,ls[p1],ls[p2],ls[p3],ls[p4]);
else return qu(mid+1,r,k-sum,rs[p1],rs[p2],rs[p3],rs[p4]);
}
void pt(int l,int r,int p){
if (l==r){
printf("%d ",f[p]);
return ;
}
int mid=(l+r)>>1;
pt(l,mid,ls[p]);
pt(mid+1,r,rs[p]);
}
}T;
int tot;
void dfs1(int f,int x){
fa[x]=f; cnt[x]=1; de[x]=de[f]+1; son[x]=0;
for (int i=nx[x];i;i=e[i].nx)if (e[i].x!=f){
dfs1(x,e[i].x);
cnt[x]+=cnt[e[i].x];
if (cnt[e[i].x]>cnt[son[x]])son[x]=e[i].x;
}
}
void dfs2(int f,int x){
top[x]=f;
T.build(1,tot,a[x],rt[fa[x]],rt[x]);
if (son[x])dfs2(f,son[x]);
for (int i=nx[x];i;i=e[i].nx)if(e[i].x!=fa[x]&&e[i].x!=son[x]){
dfs2(e[i].x,e[i].x);
}
}
int lca(int x,int y){
for (;top[x]!=top[y];){
if (de[top[x]]>de[top[y]])x=fa[top[x]];
else y=fa[top[y]];
}
if (de[x]<de[y])return x;
return y;
}
int qu(int x,int y,int k){
int Lca=lca(x,y);
return T.qu(1,tot,k,rt[x],rt[y],rt[Lca],rt[fa[Lca]]);
}
int main(){
// freopen("1.in","r",stdin);
int n,m,i,x,y,res=0,k;
read(n); read(m);
for (i=1;i<=n;i++)read(a[i]),b[i]=a[i];
sort(b+1,b+n+1);
tot=unique(b+1,b+n+1)-b-1;
for (i=1;i<=n;i++)a[i]=ch(1,tot,a[i]);
for (i=1;i<n;i++){
read(x); read(y);
add(x,y); add(y,x);
}
T.build(1,tot,rt[0]);
dfs1(0,1);
dfs2(1,1);
// for (i=1;i<=n;i++)printf("------%d-------\n",i),T.pt(1,tot,rt[i]),printf("\n");
for (;m--;){
read(x); read(y); read(k);
x^=res;
res=b[qu(x,y,k)];
printf("%d",res);
if (m)puts("");
}
return 0;
}
其實是很裸的題?qwq我太弱了