题解 P6071 【[MdOI2020] Treequery】
(在接下来的描述和图片中,用
我们考虑
1.
这表明
2.
那么这两种点到
3.
这种情况较为复杂,我们还要找出
它和
3.1.它是
答案为
3.2.它是
答案为
分析完毕。接下来研究如何实现:
求
判断一个点的孩子中是否有
求
时间复杂度
这样就可以愉快地上代码了:
#include<cstdio>
#define For(i,A,B) for(i=(A);i<=(B);++i)
#define Go(u) for(i=G[u];i;i=nxt[i])if((v=to[i])!=f[u])
const int N=200050;
char rB[1<<21],*rS,*rT,wB[(1<<21)+50];
int wp=-1;
inline char gc(){return rS==rT&&(rT=(rS=rB)+fread(rB,1,1<<21,stdin),rS==rT)?EOF:*rS++;}
inline void flush(){fwrite(wB,1,wp+1,stdout);wp=-1;}
inline int rd(){
char c=gc();
while(c<48||c>57)c=gc();
int x=c&15;
for(c=gc();c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c&15);
return x;
}
short buf[15];
inline void wt(int x){
if(wp>(1<<21))flush();
short l=-1;
while(x>9){
buf[++l]=x%10;
x/=10;
}
wB[++wp]=x|48;
while(l>=0)wB[++wp]=buf[l--]|48;
wB[++wp]='\n';
}
int G[N],to[N<<1],w[N<<1],nxt[N<<1],sz,sum[N],f[N],dep[N],dfn[N],siz[N],son[N],top[N],ps[N],dfsc,sl[N<<2],rt[N],lc[N*40],rc[N*40],tot,x,y,n;
inline void Swap(int &a,int &b){int t=a;a=b;b=t;}
inline void adde(int u,int v,int c){
to[++sz]=v;w[sz]=c;nxt[sz]=G[u];G[u]=sz;
to[++sz]=u;w[sz]=c;nxt[sz]=G[v];G[v]=sz;
}
//可持久化线段树合并部分
int add(int pre,int L,int R,int x){
int o=++tot;
if(L<R){
int M=L+R>>1;
if(x<=M){lc[o]=add(lc[pre],L,M,x);rc[o]=rc[pre];}
else{rc[o]=add(rc[pre],M+1,R,x);lc[o]=lc[pre];}
}
return o;
}
int merg(int u,int v,int L,int R){
if(!u||!v)return u|v;
int o=++tot;
if(L<R){
int M=L+R>>1;
lc[o]=merg(lc[u],lc[v],L,M);
rc[o]=merg(rc[u],rc[v],M+1,R);
}
return o;
}
int ask(int o,int L,int R){
if(!o)return 0;
if(x<=L&&y>=R)return 1;
int M=L+R>>1;
if(x<=M&&ask(lc[o],L,M))return 1;
return y>M&&ask(rc[o],M+1,R);
}
//树链剖分部分
void dfs1(int u,int fa){
int i,v,maxn=0;
siz[u]=1;
dep[u]=dep[f[u]=fa]+1;
rt[u]=add(0,1,n,u);
Go(u){
sum[v]=sum[u]+w[i];
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>maxn){son[u]=v;maxn=siz[v];}
rt[u]=merg(rt[u],rt[v],1,n);
}
}
void dfs2(int u,int topf){
top[ps[dfn[u]=++dfsc]=u]=topf;
if(son[u]){
int i,v;
dfs2(son[u],topf);
Go(u)if(v!=son[u])dfs2(v,v);
}
}
inline int lca(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])Swap(u,v);
u=f[top[u]];
}
return dep[u]<dep[v]?u:v;
}
//lca线段树部分
void build(int o,int L,int R){
if(L==R)sl[o]=L;
else{
int lc=o<<1,rc=lc|1,M=L+R>>1;
build(lc,L,M);build(rc,M+1,R);
sl[o]=lca(sl[lc],sl[rc]);
}
}
int query(int o,int L,int R){
if(x<=L&&y>=R)return sl[o];
int lc=o<<1,rc=lc|1,M=L+R>>1;
if(x<=M)if(y>M)return lca(query(lc,L,M),query(rc,M+1,R));
else return query(lc,L,M);
else return query(rc,M+1,R);
}
inline int getfa(int u){
while(u){
if(ask(rt[top[u]],1,n)){
int l=dfn[top[u]],r=dfn[u],mid;
while(l<r){
mid=l+r+1>>1;
if(ask(rt[ps[mid]],1,n))l=mid;
else r=mid-1;
}
return ps[l];
}
u=f[top[u]];
}
}
int main(){
int q,i,j,u,v,c,lans=0,p;
n=rd();q=rd();
For(i,2,n){
u=rd();v=rd();c=rd();
adde(u,v,c);
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
while(q--){
p=rd()^lans;x=rd()^lans;y=rd()^lans;
if(dfn[u=query(1,1,n)]>=dfn[p]&&dfn[u]<=dfn[p]+siz[p]-1)lans=sum[u]-sum[p]; //1.
else if(ask(rt[p],1,n))lans=0; //2.
else if(dfn[v=getfa(p)]>=dfn[u]&&dfn[v]<=dfn[u]+siz[u]-1)lans=sum[p]-sum[v]; //3.2.
else lans=sum[p]+sum[u]-(sum[v]<<1); //3.1.
wt(lans);
}
flush();
return 0;
}