P10930 异象石 题解

P10930 异象石 题解


思路分析

这题是让我们维护一个动态的树上路径并。

首先,树上路径并我们可以用虚树来求,所以如果有部分分的话,可以暴力建虚树来处理。

假设我们要求的虚树上的路径点集按照 DFS 序排好序后为 \(\{ a_i \}_1^n\),那么我们所求的值即为:

\[\frac{\sum_{i=1}^{n}dis(a_i,a_{((i+1) \bmod n)+1})}2 \]

但是直接这么做非常麻烦,我们把式子化简一下:

\[\begin{aligned} \frac{\sum_{i=1}^{n}dis(a_i,a_{((i+1) \bmod n)+1})}2 & = \frac{\sum_{i=1}^{n}dis_{a_i}+dis_{a_{((i+1) \bmod n)+1}}-2dis_{lca(a_i,a_{((i+1) \bmod n)+1})}}2 \\ & = \sum_{i=1}^n dis_{a_i} - \sum_{i=1}^{n} dis_{lca(a_i,a_{((i+1) \bmod n)+1})} \end{aligned} \]

那么剩下的就非常简单了,用一个 set<int> 实现动态维护即可。


CODE

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define FOR(i,a,b) for(int i(a);i<=(int)(b);++i)
#define DOR(i,a,b) for(int i(a);i>=(int)(b);--i)
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define EDGE(g,i,x,y) for(int i=(g).h[(x)],y=(g)[(i)].v;~i;y=(g)[i=(g)[i].nxt].v)
#define main Main();signed main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);return Main();}signed Main
using namespace std;
constexpr int N=1e5+10,lN=17,lV=lN+1;
namespace Tree {
	int n,idx;
	int dl[N],Lg[N],dep[N],dfn[N];
	int dlca[N][lV];
	ll dis[N];
	template<const int N,const int M>struct CFS {
		int tot,h[N];
		struct edge {
			int v,w,nxt;
			edge(int v=0,int w=0,int nxt=-1):v(v),w(w),nxt(nxt) {}
		} e[M];
		edge &operator[](int i) {
			return e[i];
		}
		void Init(int n) {
			tot=-1,RCL(h+1,-1,int,n);
		}
		void att(int u,int v,int w) {
			e[++tot]=edge(v,w,h[u]),h[u]=tot;
		}
		void con(int u,int v,int w) {
			att(u,v,w),att(v,u,w);
		}
	};
	CFS<N,N<<1> g;
	void dfs(int u,int fa) {
		dep[dfn[dl[u]=++idx]=u]=dep[fa]+1,dlca[dl[u]][0]=fa;
		EDGE(g,i,u,v)if(v^fa)dis[v]=dis[u]+g[i].w,dfs(v,u);
	}
	int dmin(int u,int v) {
		return dl[u]<dl[v]?u:v;
	}
	int lca(int u,int v) {
		if(u==v)return u;
		if((u=dl[u])>(v=dl[v]))swap(u,v);
		int x=Lg[v-u++];
		return dmin(dlca[u][x],dlca[v-(1<<x)+1][x]);
	}
	void Build() {
		cin>>n,g.Init(n),Lg[0]=-1;
		FOR(i,1,n)Lg[i]=Lg[i>>1]+1;
		FOR(i,2,n) {
			int u,v,w;
			cin>>u>>v>>w,g.con(u,v,w);
		}
		dfs(1,0);
		FOR(j,1,lN)FOR(i,1,n-(1<<j)+1)dlca[i][j]=dmin(dlca[i][j-1],dlca[i+(1<<(j-1))][j-1]);
	}
} using namespace Tree;
namespace VT {
	int Q;
	ll sum;
	set<int> st;
	int Pre(int u) {
		if(st.empty())return dfn[u];
		auto it=st.lower_bound(u);
		return dfn[it==st.begin()?*st.rbegin():*--it];
	}
	int Nxt(int u) {
		if(st.empty())return dfn[u];
		auto it=st.upper_bound(u);
		return dfn[it==st.end()?*st.begin():*it];
	}
	void Insert(int u) {
		int pre(Pre(dl[u])),nxt(Nxt(dl[u]));
		sum+=dis[u]-dis[lca(pre,u)]-dis[lca(u,nxt)]+dis[lca(pre,nxt)],st.insert(dl[u]);
	}
	void Erase(int u) {
		st.erase(dl[u]);
		int pre(Pre(dl[u])),nxt(Nxt(dl[u]));
		sum-=dis[u]-dis[lca(pre,u)]-dis[lca(u,nxt)]+dis[lca(pre,nxt)];
	}
	void Operate() {
		for(cin>>Q; Q; --Q) {
			char opt;
			int u;
			cin>>opt;
			if(opt=='+')cin>>u,Insert(u);
			else if(opt=='-')cin>>u,Erase(u);
			else cout<<sum<<endl;
		}
	}
} using namespace VT;
signed main() {
	Build(),Operate();
	return 0;
}

posted @ 2024-09-28 15:53  Add_Catalyst  阅读(20)  评论(0)    收藏  举报