树上问题

树上问题实际上很杂,但是也不太好去分到其他的板块去,就大概写到一起了。

P4216 [SCOI2015] 情报传递

  • 乍一看操作非常不好维护。但是发现题并没有要求在线,同时 \(c\) 是固定了,因此离线转化一下就变成了在 \(t-c\) 时刻单点修改,链上查询。

  • 那就很好做了,套路的维护每个点到根的和。差分一下就变成了子树加、查前缀。
    直接dfs序上树状数组直接做完了。

code

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+7;
int n,m,tot[N],tr[N],rt,dep[N],dfn[N],lst[N],dfncnt=0,f[N][20],ans1[N],ans2[N];
struct node{
	int op,x,y,z,tim,id;
}que[N];
bool cmp(node x,node y){return x.tim==y.tim?x.op<y.op:x.tim<y.tim;}
vector <int> q[N];
void lnk(int u,int v){q[u].push_back(v),tot[u]++;q[v].push_back(u),tot[v]++;}
void modify(int x,int w){if(x==0)return;while(x<=n)tr[x]+=w,x+=x&(-x);}
int query(int x){int res=0;while(x)res+=tr[x],x-=x&-x;return res;}
void dfs1(int u,int fa)
{
	dep[u]=dep[fa]+1;f[u][0]=fa;dfn[u]=++dfncnt;
	for(int i=1;i<=17;i++) f[u][i]=f[f[u][i-1]][i-1];
	for(int i=0;i<tot[u];i++){
		int v=q[u][i];if(v==fa) continue;
		dfs1(v,u);
	}
	lst[u]=dfncnt;
}
int lca(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=17;i>=0;i--) if(dep[f[x][i]]>=dep[y])x=f[x][i];
	if(x==y)return x;
	for(int i=17;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
	return f[x][0];
}
signed main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1,x;i<=n;i++) cin>>x,lnk(x,i),rt=x==0?i:rt;
	dfs1(rt,0);cin>>m;
	for(int i=1;i<=m;i++){
		cin>>que[i].op;que[i].id=i;
		if(que[i].op==1) cin>>que[i].x>>que[i].y>>que[i].z,que[i].tim=i-que[i].z;
		else cin>>que[i].x,que[i].tim=i;
	}
	sort(que+1,que+m+1,cmp);memset(ans1,-1,sizeof(ans1));
	for(int i=1;i<=m;i++){
		if(que[i].op==1) {int x=que[i].x,y=que[i].y,u=lca(x,y);ans1[que[i].id]=query(dfn[x])+query(dfn[y])-query(dfn[u])-query(dfn[f[u][0]]),ans2[que[i].id]=dep[x]+dep[y]-dep[u]-dep[f[u][0]];}
		else {int x=que[i].x;modify(dfn[x],1),modify(lst[x]+1,-1);}
	}
	for(int i=1;i<=m;i++) if(ans1[i]!=-1) cout<<ans2[i]<<' '<<ans1[i]<<'\n';
	return 0;
}

P4211 [LNOI2014] LCA

* 

posted @ 2025-02-24 18:23  all_for_god  阅读(15)  评论(0)    收藏  举报