【题解】Luogu P7394 「TOCO Round 1」History
看到“回到 \(x\) 后的状态”,显然考虑可持久化线段树。记开灯的为 \(1\),关灯的为 \(0\),对于每个询问只需去查某些点的权值和即可。
考虑怎么将符合条件的点转化为区间。询问的是同一深度的点,可以考虑 bfs 序。考虑如果 \(y\) 是奇数,显然答案为 \(0\);否则询问的点就是 \(x\) 的 \(\frac{y}{2}\) 级祖先在 \(x\) 这一层的后代,再去掉 \(x\) 的 \(\frac{y}{2}-1\) 级祖先在 \(x\) 这一层的后代。考虑怎么去找到询问对应的区间。对于同一棵子树的同一深度,其 bfs 序是连续的。因此可以将询问先存下来,对于每个节点建线段树,存储某一深度的 bfs 序最大值和最小值。线段树合并即可。
时间复杂度分析,处理操作时每次都为 \(O(\log n)\),所有线段树合并的总时间复杂度为 \(O(n\log n)\),于是总的时间复杂度就为 \(O((n+m)\log n)\)。
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define pb push_back
#define pii pair<int,int>
#define mp make_pair
#define fir first
#define sec second
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
int n,m,dep[maxn];
int anc[maxn][22];
int bfn[maxn];
queue<int> q;
vector<int> e[maxn];
vector<pii> quj[maxn];
struct{
int opt,x,y;
int l1,r1,l2,r2;
}wt[maxn];
il void dfs1(int u,int fa){
dep[u]=dep[fa]+1;
anc[u][0]=fa;
for(int i=1;i<=20;i++){
anc[u][i]=anc[anc[u][i-1]][i-1];
}
for(int v:e[u]){
if(v==fa){
continue;
}
dfs1(v,u);
}
}
il int ganc(int u,int k){
int tmp=0;
while(k){
if(k&1){
u=anc[u][tmp];
}
k>>=1,tmp++;
}
return u;
}
il void bfs(){
int cnt=0;
q.push(1);
while(q.size()){
int u=q.front();
q.pop(),bfn[u]=++cnt;
for(int v:e[u]){
if(!bfn[v]){
q.push(v);
}
}
}
}
int rt[maxn],tot,ls[maxn*40],rs[maxn*40],sum[maxn*40],mn[maxn*40],mx[maxn*40];
il int New(){
tot++;
ls[tot]=rs[tot]=sum[tot];
mn[tot]=inf,mx[tot]=-inf;
return tot;
}
il void pushup(int id){
sum[id]=sum[ls[id]]+sum[rs[id]];
}
il void build(int &id,int l,int r){
id=New();
if(l==r){
return ;
}
int mid=(l+r)>>1;
build(ls[id],l,mid);
build(rs[id],mid+1,r);
}
il void add(int &id,int l,int r,int p,int v){
if(!id){
id=New();
}
if(l==r){
mn[id]=min(mn[id],v);
mx[id]=max(mx[id],v);
return ;
}
int mid=(l+r)>>1;
if(p<=mid){
add(ls[id],l,mid,p,v);
}
else{
add(rs[id],mid+1,r,p,v);
}
mn[id]=min(mn[ls[id]],mn[rs[id]]);
mx[id]=max(mx[ls[id]],mx[rs[id]]);
}
il void upd(int &id,int fr,int l,int r,int p){
id=New();
if(l==r){
sum[id]=sum[fr]^1;
return ;
}
int mid=(l+r)>>1;
if(p<=mid){
rs[id]=rs[fr];
upd(ls[id],ls[fr],l,mid,p);
}
else{
ls[id]=ls[fr];
upd(rs[id],rs[fr],mid+1,r,p);
}
pushup(id);
}
il int merge(int p,int q,int l,int r){
if(!p||!q){
return p+q;
}
if(l==r){
int x=New();
mn[x]=min(mn[p],mn[q]);
mx[x]=max(mx[p],mx[q]);
return x;
}
int mid=(l+r)>>1,x=New();
ls[x]=merge(ls[p],ls[q],l,mid);
rs[x]=merge(rs[p],rs[q],mid+1,r);
mn[x]=min(mn[ls[x]],mn[rs[x]]);
mx[x]=max(mx[ls[x]],mx[rs[x]]);
return x;
}
il int query(int id,int L,int R,int l,int r){
if(l>r||!id){
return 0;
}
if(L>=l&&R<=r){
return sum[id];
}
int mid=(L+R)>>1,res=0;
if(l<=mid){
res+=query(ls[id],L,mid,l,r);
}
if(r>mid){
res+=query(rs[id],mid+1,R,l,r);
}
return res;
}
il int qmn(int id,int l,int r,int p){
if(l==r){
return mn[id];
}
int mid=(l+r)>>1;
return p<=mid?qmn(ls[id],l,mid,p):qmn(rs[id],mid+1,r,p);
}
il int qmx(int id,int l,int r,int p){
if(l==r){
return mx[id];
}
int mid=(l+r)>>1;
return p<=mid?qmx(ls[id],l,mid,p):qmx(rs[id],mid+1,r,p);
}
il void dfs2(int u,int fa){
add(rt[u],1,n,dep[u],bfn[u]);
for(int v:e[u]){
if(v==fa){
continue;
}
dfs2(v,u);
rt[u]=merge(rt[u],rt[v],1,n);
}
for(pii v:quj[u]){
int k=v.fir,id=v.sec;
if(id>0){
wt[id].l1=qmn(rt[u],1,n,k);
wt[id].r1=qmx(rt[u],1,n,k);
}
else{
id=-id;
wt[id].l2=qmn(rt[u],1,n,k);
wt[id].r2=qmx(rt[u],1,n,k);
}
}
}
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n;
for(int i=1,u,v;i<n;i++){
cin>>u>>v;
e[u].pb(v),e[v].pb(u);
}
dfs1(1,0),bfs();
cin>>m;
for(int i=1,opt,x,y;i<=m;i++){
cin>>opt>>x;
wt[i].opt=opt,wt[i].x=x;
if(opt==2){
cin>>y;
wt[i].y=y;
if((y&1)||!y){
continue;
}
y>>=1;
if(y>=dep[x]){
continue;
}
x=ganc(wt[i].x,y);
quj[x].pb(mp(dep[wt[i].x],i));
x=ganc(wt[i].x,y-1);
quj[x].pb(mp(dep[wt[i].x],-i));
}
}
mn[0]=inf,mx[0]=-inf;
dfs2(1,0);
tot=0;
build(rt[0],1,n);
for(int i=1,opt,x,y;i<=m;i++){
opt=wt[i].opt,x=wt[i].x,y=wt[i].y;
switch(opt){
case 1:{
upd(rt[i],rt[i-1],1,n,bfn[x]);
break;
}
case 2:{
rt[i]=rt[i-1];
if(y&1){
cout<<"0\n";
}
else if(!y){
cout<<query(rt[i],1,n,bfn[x],bfn[x])<<"\n";
}
else{
y>>=1;
if(y>=dep[x]){
cout<<"0\n";
}
else{
cout<<query(rt[i],1,n,wt[i].l1,wt[i].l2-1)+query(rt[i],1,n,wt[i].r2+1,wt[i].r1)<<"\n";
}
}
break;
}
default:{
rt[i]=rt[x];
break;
}
}
}
return 0;
}
}
int main(){return asbt::main();}

浙公网安备 33010602011771号