BZOJ2588 - Count on a tree
题意简述
给出一棵带点权的
分析
记节点到根的点权和为
实现
与普通的可持久化线段树差别不大,只是在查询的时候要多传几个参数。
代码
//Count on a tree
#include <cstdio>
#include <algorithm>
using namespace std;
inline char gc()
{
static char now[1<<16],*S,*T;
if(S==T) {T=(S=now)+fread(now,1,1<<16,stdin); if(S==T) return EOF;}
return *S++;
}
inline int read()
{
int x=0,f=1; char ch=gc();
while(ch<'0'||'9'<ch) {if(ch=='-') f=-1; ch=gc();}
while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int const N=1e5+10;
int n,m,v[N];
int num,map[N];
struct rec{int v,id;} a0[N];
bool cmpV(rec x,rec y) {return x.v<y.v;}
int cnt,h[N];
struct edge{int v,nxt; edge(int u=0,int v1=0){v=v1,nxt=h[u],h[u]=cnt;}} ed[N<<1];
#define s sg[s0]
int sgCnt,rt[N];
struct seg{int cnt; int L,R;} sg[N*20];
void update(int s0) {s.cnt=sg[s.L].cnt+sg[s.R].cnt;}
void ins(int &s0,int fr,int to,int v)
{
sg[++sgCnt]=s; s0=sgCnt;
if(fr==to) {s.cnt++; return;}
int mid=fr+to>>1;
if(v<=mid) ins(s.L,fr,mid,v);
else ins(s.R,mid+1,to,v);
update(s0);
}
int query(int s1,int s2,int s3,int s4,int fr,int to,int k)
{
if(fr==to) return fr;
int cntL=sg[sg[s1].L].cnt+sg[sg[s2].L].cnt-sg[sg[s3].L].cnt-sg[sg[s4].L].cnt;
int mid=fr+to>>1;
if(k<=cntL) return query(sg[s1].L,sg[s2].L,sg[s3].L,sg[s4].L,fr,mid,k);
else return query(sg[s1].R,sg[s2].R,sg[s3].R,sg[s4].R,mid+1,to,k-cntL);
}
int fa[N][20],dpt[N];
void trform(int u)
{
ins(rt[u]=rt[fa[u][0]],1,num,v[u]);
for(int i=1;i<=17;i++) fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=h[u];i;i=ed[i].nxt)
{
int v=ed[i].v;
if(v!=fa[u][0]) fa[v][0]=u,dpt[v]=dpt[u]+1,trform(v);
}
}
int lca(int u,int v)
{
if(dpt[u]<dpt[v]) swap(u,v);
for(int i=17;i>=0;i--) if(dpt[fa[u][i]]>=dpt[v]) u=fa[u][i];
for(int i=17;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
return u==v?u:fa[u][0];
}
int main()
{
n=read(); m=read();
for(int i=1;i<=n;i++) a0[i].v=read(),a0[i].id=i;
sort(a0+1,a0+n+1,cmpV);
num=0;
for(int i=1;i<=n;i++)
{
if(a0[i-1].v!=a0[i].v) map[++num]=a0[i].v;
v[a0[i].id]=num;
}
cnt=0;
for(int i=1;i<=n-1;i++)
{
int u=read(),v=read();
ed[++cnt]=edge(u,v); ed[++cnt]=edge(v,u);
}
rt[0]=sgCnt=0;
fa[1][0]=0,dpt[1]=1,trform(1);
int ans=0;
for(int owo=1;owo<=m;owo++)
{
int u=read()^ans,v=read(),k=read(); int w=lca(u,v);
printf("%d",ans=map[query(rt[u],rt[v],rt[w],rt[fa[w][0]],1,num,k)]);
if(owo!=m) printf("\n");
}
return 0;
}
注意
本题强制在线,查询时仅需要将
最后一次查询不要输出\n,否则会PE。