题解 - 保卫王国(倍增做法)

题目意思

题目传送门

S o l \mathrm{Sol} Sol

首先对于每次分别做 dp 是 O ( n 2 ) O(n^2) O(n2),即设 f u , 0 / 1 f_{u,0/1} fu,0/1 表示这个点选不选的最小代价,转移就是简单背包: f u , 0 = ∑ v ∈ u f v , 1 , f u , 1 = ∑ v ∈ u min ⁡ ( f v , 0 , f v , 1 ) f_{u,0}=\sum\limits_{v∈u}f_{v,1},f_{u,1}=\sum\limits_{v∈u}\min(f_{v,0},f_{v,1}) fu,0=vufv,1,fu,1=vumin(fv,0,fv,1)

我们考虑到每次修改只修改 u ∼ v u\sim v uv 两点到其 l c a lca lca 上的链以及 l c a lca lca 到根的链的贡献所以我们考虑每次修改贡献的加减。

于是我们考虑倍增,设 g 0 / 1 , 0 / 1 , u , i g_{0/1,0/1,u,i} g0/1,0/1,u,i 表示 u u u 是否选, u u u 2 i 2^i 2i 祖先选不选的 dp 值,这个预处理还是不难的,即我们每次考虑 u u u 2 i − 1 2^{i-1} 2i1 祖先的是否取状态来合并即可,具体实现可以看代码。

然后我们来考虑如何转移答案:假设 u u u 新的 dp 值为 h x h_x hx 那么对于更新 f a u fa_u fau 的 dp 值,莫过于选或不选两种情况: f f a u , 0 − f u , 1 + h x f_{fa_u,0}-f_{u,1}+h_x ffau,0fu,1+hx f f a u , 1 − min ⁡ ( f u , 0 , f u , 1 ) + h x f_{fa_u,1}-\min(f_{u,0},f_{u,1})+h_x ffau,1min(fu,0,fu,1)+hx

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

C o d e \mathrm{Code} Code

const int mod=1e9+7;
const int mo=998244353;
const int N=5e5+5;

int n,m,dp[N][2],g[2][2][21][N];
int dep[N],f[N][22],a[N];
vector<int> G[N];
char s[5];

inline void dfs(int u,int fa)
{
    
    
	dep[u]=dep[fa]+1;
	f[u][0]=fa;
	For(i,1,19) f[u][i]=f[f[u][i-1]][i-1];
	dp[u][1]=a[u];
	g[0][0][0][u]=1e15;
	For(i,0,(int)G[u].size()-1) 
	{
    
    
		int v=G[u][i];
		if(v==fa) continue;
		dfs(v,u);
		dp[u][0]+=dp[v][1];
		dp[u][1]+=min(dp[v][1],dp[v][0]);
	}
}

inline void Dfs(int u) 
{
    
    
	g[1][0][0][u]=dp[f[u][0]][0]-dp[u][1];
	g[1][1][0][u]=g[0][1][0][u]=dp[f[u][0]][1]-min(dp[u][0],dp[u][1]);
	For(i,1,19)
	{
    
    
		int fa=f[u][i-1];
		g[0][0][i][u]=min(g[0][0][i-1][u]+g[0][0][i-1][fa],g[0][1][i-1][u]+g[1][0][i-1][fa]);
		g[0][1][i][u]=min(g[0][1][i-1][u]+g[1][1][i-1][fa],g[0][0][i-1][u]+g[0][1][i-1][fa]);
		g[1][0][i][u]=min(g[1][0][i-1][u]+g[0][0][i-1][fa],g[1][1][i-1][u]+g[1][0][i-1][fa]);
		g[1][1][i][u]=min(g[1][0][i-1][u]+g[0][1][i-1][fa],g[1][1][i-1][u]+g[1][1][i-1][fa]);
	}
	For(i,0,(int)G[u].size()-1) 
	{
    
    
		int v=G[u][i];
		if(v==f[u][0]) continue;
		Dfs(v);
	}
}

signed main()
{
    
    
	io.read(n),io.read(m);
	scanf("%s",s+1);
	For(i,1,n) io.read(a[i]);
	For(i,1,n-1)
	{
    
    
		int x,y;
		io.read(x),io.read(y);
		G[x].pb(y),G[y].pb(x);
	}
	dfs(1,0);
	Dfs(1);
	for (;m--;)
	{
    
    
		int a,x,b,y,L;
		io.read(a),io.read(x),io.read(b),io.read(y);
		if(dep[a]<dep[b]) swap(x,y),swap(a,b);
		int u0=1e15,u1=1e15,v0=1e15,v1=1e15,l1=1e15,l0=1e15,ans;
		(x)?u1=dp[a][1]:u0=dp[a][0];
		(y)?v1=dp[b][1]:v0=dp[b][0];
		Dow(i,19,0) if(dep[a]-(1ll<<i)>=dep[b]) 
		{
    
    
			int t0=u0,t1=u1;
			u0=min(t0+g[0][0][i][a],t1+g[1][0][i][a]);
			u1=min(t0+g[0][1][i][a],t1+g[1][1][i][a]);
			a=f[a][i];
		}
		if(a==b) L=a,(y)?l1=u1:l0=u0;
		else 
		{
    
    
			Dow(i,19,0) if(f[a][i]^f[b][i]) 
			{
    
    
				int t0=u0,t1=u1;
				int s0=v0,s1=v1;
				u0=min(t0+g[0][0][i][a],t1+g[1][0][i][a]);
				u1=min(t0+g[0][1][i][a],t1+g[1][1][i][a]);
				v0=min(s0+g[0][0][i][b],s1+g[1][0][i][b]);
				v1=min(s0+g[0][1][i][b],s1+g[1][1][i][b]);
				a=f[a][i],b=f[b][i];
			}
			L=f[a][0];
			l0=dp[L][0]-dp[a][1]-dp[b][1]+u1+v1;
			l1=dp[L][1]-min(dp[a][0],dp[a][1])-min(dp[b][0],dp[b][1])+min(u1,u0)+min(v1,v0);
		}
		if(L==1) ans=min(l0,l1);
		else 
		{
    
    
			Dow(i,19,0) if(dep[L]-(1ll<<i)>1) 
			{
    
    
				int t0=l0,t1=l1;
				l0=min(t0+g[0][0][i][L],t1+g[1][0][i][L]);
				l1=min(t0+g[0][1][i][L],t1+g[1][1][i][L]);
				L=f[L][i];
			}
			ans=min(dp[1][0]-dp[L][1]+l1,dp[1][1]-min(dp[L][0],dp[L][1])+min(l0,l1));
		}
		if(ans==1e15) ans=-1;
		io.write(ans); 
		puts("");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/wangyiyang2/article/details/108589528