【题解】P6071 『MdOI R1』Treequery
题目描述
给定一棵 个点的无根树,边有边权。
令 表示树上 之间的简单路径上的所有边的集合,特别地,当 时,。
你需要 实时 回答 个询问,每个询问给定 ,请你求出集合 中所有边的边权和,即 的交所包含的边的边权和。
通俗的讲,你需要求出 到 内每一个点的简单路径的公共部分长度。
题解
套路题感觉没什么好讲的。
既然是公共部分长度,那么只有所有点都在当前点子树内或者都不在才有解。
对于在当前点子树内,答案为l到r中dfs虚最小和最大的两点到当前点的距离。
对于其他的,即是找到当前点向上第一次与l到r点构成的虚树相交的位置,查找dfs序上前驱后继和当前点的lca即可。
提示:树上问题与dfs序一般有优美的性质。
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
int f=1,j=0;
char w=getchar();
while(!isdigit(w)){
if(w=='-')f=-1;
w=getchar();
}
while(isdigit(w)){
j=j*10+w-'0';
w=getchar();
}
return f*j;
}
const int N=1000010;
int rt[N],tr[N*40],ls[N*40],rs[N*40],tot;
int head[N],to[N*2],fro[N*2],w[N*2],tail;
int n,q,dep[N],tort[N],fa[N][21];
int dfn[N],siz[N],bel[N],cnt;
inline void adlin(int x,int y,int z){
to[++tail]=y,fro[tail]=head[x],head[x]=tail,w[tail]=z;
return ;
}
void dfs(int u,int Fa){
dfn[++cnt]=u,bel[u]=cnt,siz[u]=1;
fa[u][0]=Fa;
dep[u]=dep[Fa]+1;
for(int k=1;(1<<k)<dep[u];k++)fa[u][k]=fa[fa[u][k-1]][k-1];
for(int k=head[u];k;k=fro[k]){
int v=to[k];
if(v==Fa)continue;
else tort[v]=tort[u]+w[k],dfs(v,u),siz[u]+=siz[v];
}
return ;
}
inline int lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int k=20;k>=0;k--){
if(dep[fa[x][k]]>=dep[y])x=fa[x][k];
}
for(int k=20;k>=0;k--){
if(fa[x][k]!=fa[y][k])x=fa[x][k],y=fa[y][k];
}
if(x!=y)x=fa[x][0];
return x;
}
inline void update(int u){
tr[u]=tr[ls[u]]+tr[rs[u]];
return ;
}
void modify(int &u,int v,int l,int r,int aim){
u=++tot;
// cout<<u<<" "<<v<<"-"<<l<<" "<<r<<"\n";
if(l==r){
// cout<<u<<":"<<l<<" "<<r<<":"<<1<<"\n";
return tr[u]=1,void(0);
}
int mid=(l+r)/2;
if(aim<=mid)rs[u]=rs[v],modify(ls[u],ls[v],l,mid,aim);
else ls[u]=ls[v],modify(rs[u],rs[v],mid+1,r,aim);
update(u);
// cout<<u<<" "<<v<<":"<<l<<" "<<r<<"-"<<ls[u]<<" "<<rs[u]<<":"<<tr[u]<<"\n";
return ;
}
int querysm(int u,int v,int l,int r,int L,int R){
if(!u||tr[u]-tr[v]==0)return 0;
if(L<=l&&r<=R)return tr[u]-tr[v];
int mid=(l+r)/2,ansn=0;
if(L<=mid)ansn+=querysm(ls[u],ls[v],l,mid,L,R);
if(R>mid)ansn+=querysm(rs[u],rs[v],mid+1,r,L,R);
return ansn;
}
int queryrk(int u,int v,int l,int r,int k){
if(!u||tr[u]-tr[v]==0)return 0;
if(l==r)return l;
int mid=(l+r)/2;
if(tr[ls[u]]-tr[ls[v]]>=k)return queryrk(ls[u],ls[v],l,mid,k);
else return queryrk(rs[u],rs[v],mid+1,r,k-(tr[ls[u]]-tr[ls[v]]));
}
//void debug(int u,int l,int r){
// if(!u)return ;
// cout<<u<<":"<<l<<" "<<r<<"-"<<ls[u]<<" "<<rs[u]<<":"<<tr[u]<<"\n";
// if(l==r)return ;
// int mid=(l+r)/2;
// debug(ls[u],l,mid),debug(rs[u],mid+1,r);
// return ;
//}
int calfir(int p,int l,int r){
if(l<=p&&p<=r)return 0;
int fros=querysm(rt[r],rt[l-1],1,n,1,bel[p]);
int x=dfn[queryrk(rt[r],rt[l-1],1,n,fros+1)];
int y=dfn[queryrk(rt[r],rt[l-1],1,n,fros+r-l+1)];
x=lca(x,y);
return tort[x]-tort[p];
}
signed main(){
// freopen("P6071_8.in","r",stdin);
// freopen("ans.out","w",stdout);
n=rd(),q=rd();
for(int i=1;i<n;i++){
int x=rd(),y=rd(),z=rd();
adlin(x,y,z),adlin(y,x,z);
}
dfs(1,0);
for(int i=1;i<=n;i++)modify(rt[i],rt[i-1],1,n,bel[i]);
// for(int i=1;i<=n;i++)cout<<rt[i]<<" ";
// cout<<"\n";
// debug(rt[2],1,n),cout<<"\n";
// for(int i=1;i<=n;i++)cout<<i<<":"<<dep[i]<<" "<<tort[i]<<":"<<siz[i]<<"-"<<bel[i]<<"\n";
int lastans=0;
for(int t=1;t<=q;t++){
// cerr<<t<<":";
int p=rd()^lastans,l=rd()^lastans,r=rd()^lastans;
int intr=querysm(rt[r],rt[l-1],1,n,bel[p],bel[p]+siz[p]-1);
// cerr<<"T:"<<t<<":"<<p<<"-"<<l<<" "<<r<<":"<<intr<<"\n";
if(l<=p&&p<=r){
printf("%d\n",lastans=0);
// cerr<<"sub=1\n";
// cerr<<lastans<<"\n";
continue;
}
else if(intr==r-l+1){
printf("%d\n",lastans=calfir(p,l,r));
// cerr<<"sub=2\n";
// cerr<<lastans<<"\n";
}
else if(intr==0){
int fros=querysm(rt[r],rt[l-1],1,n,1,bel[p]);
int x=queryrk(rt[r],rt[l-1],1,n,fros);
int y=queryrk(rt[r],rt[l-1],1,n,fros+1);
x=dfn[x],y=dfn[y];
x=lca(x,p),y=lca(y,p);
// cout<<"find:"<<x<<" "<<y<<"\n";
if(dep[x]<dep[y])x=y;
lastans=tort[p]-tort[x];
intr=querysm(rt[r],rt[l-1],1,n,bel[x],bel[x]+siz[x]-1);
if(intr==r-l+1)lastans+=calfir(x,l,r);
printf("%d\n",lastans);
// cerr<<"sub=3\n";
// cerr<<lastans<<"\n";
}
else printf("%d\n",lastans=0);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】