LibreOJ 2955. 「NOIP2018」保卫王国【动态DP】

LibreOJ 2955. 「NOIP2018」保卫王国

果然是一道裸题,动态DP,必须选就设权值为0,不选设权值为 ∞ \infty 就可以了。

转移矩阵 [ g x , 1 g x , 1 g x , 0 ∞ ] ∗ [ f v , 1 f v , 0 ] = [ f x , 1 f x , 0 ] \begin{bmatrix} g_{x,1} & g_{x,1} \\ g_{x,0} & \infty \end{bmatrix}* \begin{bmatrix} f_{v,1} \\ f_{v,0}\end{bmatrix}=\begin{bmatrix} f_{x,1} \\ f_{x,0}\end{bmatrix} [gx,1gx,0gx,1][fv,1fv,0]=[fx,1fx,0]

#include
#include
#include
using namespace std;
typedef long long LL;
const int MAXN=1e5+5;const LL inf=1e17;
int n,m;LL F[MAXN][2],a[MAXN];
int cnt,Dfn[MAXN],IDfn[MAXN],Siz[MAXN],Top[MAXN],Son[MAXN],Fa[MAXN],End[MAXN];
#include
int read(){
	int ret=0;char ch=getchar();bool f=1;
	for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
	for(; isdigit(ch);ch=getchar()) ret=ret*10+ch-48;
	return f?ret:-ret;
}
struct Maxtin{
	LL g[2][2];
	Maxtin(){memset(g,127,sizeof(g));}
	Maxtin operator *(const Maxtin b)const{
		Maxtin c;
		for(int i=0;i<2;i++)
		for(int j=0;j<2;j++)
		for(int k=0;k<2;k++)
		c.g[i][j]=min(c.g[i][j],g[i][k]+b.g[k][j]);
		return c;
	}
}Tre[MAXN<<2],Val[MAXN];
struct Edge{
	int tot,lnk[MAXN],nxt[MAXN<<1],son[MAXN<<1];
	void Add(int x,int y){nxt[++tot]=lnk[x];lnk[x]=tot;son[tot]=y;}
}E;
void DFS(int x,int fa){
	F[x][0]=0,F[x][1]=a[x];
	for(int j=E.lnk[x];j;j=E.nxt[j])
	if(E.son[j]!=fa){
		DFS(E.son[j],x);
		F[x][0]+=F[E.son[j]][1];
		F[x][1]+=min(F[E.son[j]][1],F[E.son[j]][0]);
	}
}
void First(int x,int fa){
	Siz[x]=1;Fa[x]=fa;
	for(int j=E.lnk[x];j;j=E.nxt[j])
	if(E.son[j]!=fa){
		First(E.son[j],x),Siz[x]+=Siz[E.son[j]];
		if(Siz[Son[x]]<Siz[E.son[j]]) Son[x]=E.son[j];
	}
}
void Second(int x,int T){
	if(Dfn[x]) return;
	Dfn[x]=++cnt,IDfn[cnt]=x,Top[x]=T,End[T]=x;
	if(!Son[x]) return;Second(Son[x],T);
	for(int j=E.lnk[x];j;j=E.nxt[j]) Second(E.son[j],E.son[j]);
}
void Build(int rt,int L,int R){
	if(L==R){
		int x=IDfn[L],g0=0,g1=a[x];
		for(int j=E.lnk[x];j;j=E.nxt[j])
		if(E.son[j]!=Fa[x]&&E.son[j]!=Son[x]) g0+=F[E.son[j]][1],g1+=min(F[E.son[j]][0],F[E.son[j]][1]);
		Tre[rt].g[1][0]=g0,Tre[rt].g[1][1]=inf,Tre[rt].g[0][0]=Tre[rt].g[0][1]=g1;Val[L]=Tre[rt];
		return;
	}
	int mid=(R+L)>>1;
	Build(rt<<1,L,mid);Build(rt<<1|1,mid+1,R);
	Tre[rt]=Tre[rt<<1]*Tre[rt<<1|1];
}
void Insert(int rt,int L,int R,int p){
	if(L==R){Tre[rt]=Val[L];return;}
	int mid=(R+L)>>1;
	if(p<=mid) Insert(rt<<1,L,mid,p);else Insert(rt<<1|1,mid+1,R,p);
	Tre[rt]=Tre[rt<<1]*Tre[rt<<1|1];
}
Maxtin Query(int rt,int L,int R,int l,int r){
	if(l<=L&&R<=r) return Tre[rt];
	int mid=(R+L)>>1;
	if(r<=mid) return Query(rt<<1,L,mid,l,r);else
	if(l>mid) return Query(rt<<1|1,mid+1,R,l,r);else
	return Query(rt<<1,L,mid,l,r)*Query(rt<<1|1,mid+1,R,l,r);
}
void Change(int x,LL f){
	Val[Dfn[x]].g[0][0]=(Val[Dfn[x]].g[0][1]+=f);
	Maxtin Now,Pre;
	while(x){
		Pre=Query(1,1,n,Dfn[Top[x]],Dfn[End[Top[x]]]);
		Insert(1,1,n,Dfn[x]);
		Now=Query(1,1,n,Dfn[Top[x]],Dfn[End[Top[x]]]);
		x=Fa[Top[x]];if(x==0) break;
		Val[Dfn[x]].g[1][0]+=Now.g[0][0]-Pre.g[0][0];
		Val[Dfn[x]].g[0][0]=(Val[Dfn[x]].g[0][1]+=min(Now.g[0][0],Now.g[1][0])-min(Pre.g[0][0],Pre.g[1][0]));
	}
}
int main(){
//	freopen("2955.in","r",stdin);
//	freopen("2955.out","w",stdout);
	n=read(),m=read();getchar(),getchar();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1,x,y;i<n;i++) x=read(),y=read(),E.Add(x,y),E.Add(y,x);
	First(1,0),Second(1,1),DFS(1,0);Build(1,1,n);
	for(int i=1;i<=m;i++){
		int x=read(),s=read(),y=read(),t=read();
		if((Fa[x]==y||Fa[y]==x)&&((s||t)==0)){printf("-1\n");continue;}
		Change(x,s?-a[x]:inf-a[x]);Change(y,t?-a[y]:inf-a[y]);
		Maxtin Now=Query(1,1,n,Dfn[1],Dfn[End[1]]);
		LL Ans=min(Now.g[0][0],Now.g[1][0])+a[x]*s+a[y]*t;
		printf("%lld\n",Ans);
		Change(x,s?a[x]:a[x]-inf);Change(y,t?a[y]:a[y]-inf);
	}
	return 0;
}

你可能感兴趣的:(LibreOJ,动态DP)