求助,与暴力同分
查看原帖
求助,与暴力同分
190926
Diwanul楼主2020/8/18 15:53

本题思路同第2篇题解,倍增解决,但细节实现可能不同(应该不会有问题吧)。与暴力m遍O(n)树形DP同分……不过是WA不是TLE。

代码如下

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
ll f[100010][2],a[100010],g[100010][2],h[100010][2][20][2];
int te,fa[100010][20],head[100010],de[100010];
struct edge{
	int to,nex;
}e[200010];
	
void Add(int a,int b){
	e[++te].nex=head[a];
	e[te].to=b;
	head[a]=te;
}

void Dfs1(int x){
	for(register int i=0;i<19;i++)fa[x][i+1]=fa[fa[x][i]][i];
	for(register int i=head[x];i;i=e[i].nex)
		if(e[i].to!=fa[x][0])
			fa[e[i].to][0]=x,de[e[i].to]=de[x]+1,Dfs1(e[i].to),f[x][0]+=f[e[i].to][1],f[x][1]+=min(f[e[i].to][0],f[e[i].to][1]);
	f[x][1]+=a[x];
}

void Dfs2(int x){
	for(register int i=head[x];i;i=e[i].nex)
		if(e[i].to!=fa[x][0])
			g[e[i].to][0]=f[x][1]+g[x][1]-min(f[e[i].to][0],f[e[i].to][1]),g[e[i].to][1]=min(g[e[i].to][0],g[x][0]+f[x][0]-f[e[i].to][1]),Dfs2(e[i].to);
}

void Cl(int a,int za,int b,int zb){
	if(de[a]<de[b])swap(a,b),swap(za,zb);
	ll sa[2]={1ll<<62,1ll<<62},sb[2]={1ll<<62,1ll<<62};
	sa[za]=f[a][za],sb[zb]=f[b][zb];
//	printf("%d %d %lld %lld %lld %lld\n",a,b,sa[0],sa[1],sb[0],sb[1]);
	for(register int i=19;i>-1;i--)
		if(de[a]-(1<<i)>=de[b]){
			ll ta[2]={1ll<<62,1ll<<62};
			for(register int k=0;k<2;k++)
				for(register int l=0;l<2;l++)
					ta[k]=min(ta[k],sa[l]+h[a][l][i][k]);
			sa[0]=ta[0],sa[1]=ta[1],a=fa[a][i];
//			printf("%d %d %lld %lld %lld %lld\n",a,b,sa[0],sa[1],sb[0],sb[1]);
		}
//	printf("%d %d\n",a,b);
	if(a==b){
		printf("%lld\n",sa[zb]+g[b][zb]);
		return;
	}
	for(register int i=19;i>-1;i--)
		if(fa[a][i]!=fa[b][i]){
			ll ta[2]={1ll<<62,1ll<<62},tb[2]={1ll<<62,1ll<<62};
			for(register int k=0;k<2;k++)
				for(register int l=0;l<2;l++)
					ta[k]=min(ta[k],sa[l]+h[a][l][i][k]),tb[k]=min(tb[k],sb[l]+h[b][l][i][k]);
			sa[0]=ta[0],sa[1]=ta[1],sb[0]=tb[0],sb[1]=tb[1],fa[a][i],b=fa[b][i];
		}
//	printf("%d %d\n",a,b);
	printf("%lld\n",min(g[fa[a][0]][0]+f[fa[a][0]][0]-f[a][1]-f[b][1]+sa[1]+sb[1],g[fa[a][0]][1]+f[fa[a][0]][1]-min(f[a][1],f[a][0])-min(f[b][0],f[b][1])+min(sa[0],sa[1])+min(sb[0],sb[1])));
}

int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	char c=getchar();
	while(c!='1'&&c!='2'&&c!='3')c=getchar();
	for(register int i=1;i<=n;i++)scanf("%d",a+i);
	for(register int i=1;i<n;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		Add(a,b);
		Add(b,a);
	}
	Dfs1(1);
	Dfs2(1);
	for(register int i=1;i<=n;i++){
		h[i][0][0][0]=0x3f3f3f3f;
		h[i][1][0][0]=f[fa[i][0]][0]-f[i][1];
		h[i][1][0][1]=h[i][0][0][1]=f[fa[i][0]][1]-min(f[i][0],f[i][1]);
	}
	for(register int j=1;j<20;j++)
		for(register int i=1;i<=n;i++)
			for(register int k=0;k<2;k++)
				for(register int l=0;l<2;l++){
					h[i][k][j][l]=0x3f3f3f3f;
					for(register int o=0;o<2;o++)
						h[i][k][j][l]=min(h[i][k][j][l],h[i][k][j-1][o]+h[fa[i][j-1]][o][j-1][l]);
				}
	while(m--){
		int a,b,za,zb;
		scanf("%d%d%d%d",&a,&za,&b,&zb);
		if(!za&&!zb){
			bool bb=0;
			for(register int i=head[a];i;i=e[i].nex)
				if(e[i].to==b)
					bb=1;
			if(bb){
				puts("-1");
				continue;
			}
		}
		Cl(a,za,b,zb);
	}
	return 0;
}
2020/8/18 15:53
加载中...