【2019集訓隊互測】公園(廣義串並聯圖)(動態DP)

傳送門


題解:

只提一下記個要用的性質,證明去集訓隊論文裏面看。

  1. 滿足題意限制的圖稱爲廣義串並聯圖。
  2. 任何一個廣義串並聯圖,去掉重邊之後邊數不超過點數的兩倍。
  3. 任何一個廣義串並聯圖可以由如下的方式構造:初始只有一個點,每次可以選擇 1)加一個點,並和圖中原有點連一條邊,2)選擇兩個直接相連的點,新加一個點與這兩個點相連,並且可以選擇是否刪去原來連接這兩個點的邊。

當然廣義串並聯圖也是平面圖,不過這個性質這道題用不到。

而且廣義串並聯圖上還可以出奇妙的 O(n2)O(n^2) 異或高斯消元題(好幾個月之前的idea了),等我退役之後可能會出出來吧。

那麼就需要做的事情就很明顯了,我們考慮對構造反着來,直到圖只剩下一個節點即可。

需要支持的操作有1)刪一個度數爲 11 的點,2)縮一個度數爲 22 的點並消去重邊。

容易發現每個點維護兩種顏色的權值,每條邊要維護兩邊四種情況的權值,然後就可以DP了。

加上修改,考慮動態DP。

乍一看是沒法用矩陣維護的,一條邊的四個權值其實需要用 1×41\times 4 的向量而不是 2×22\times 2 的矩陣來維護。

然後隨便維護一下動態DP就行了,算輕兒子之和分類討論有點麻煩。


代碼:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

namespace IO{

inline char gc(){
	static cs int Rlen=3e7+7;static char buf[Rlen],*p1,*p2;
	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++; 
}template<typename T>T get_integer(){
	char c;bool f=false;while(!isdigit(c=gc()))f=c=='-';T x=c^48;
	while(isdigit(c=gc()))x=((x+(x<<2))<<1)+(c^48);return f?-x:x;
}inline int gi(){return get_integer<int>();}
inline ll gl(){return get_integer<ll>();}

char obuf[(int)(3e7+7)],*oh=obuf,ch[23];
template<typename T>void print(T a,char c){
	if(a<0)*oh++='-',a=-a;int tl=0;
	do ch[++tl]=a%10; while(a/=10);
	while(tl)*oh++=ch[tl--]^48;*oh++=c;
}struct obuf_flusher{~obuf_flusher(){fwrite(obuf,1,oh-obuf,stdout);}}Flusher;

}using IO::gi;
using IO::gl;
using IO::print;

using std::cerr;
using std::cout;
#define fi first
#define se second

template<typename T>void cmax(T &a,cs T &b){a<b?a=b:a;}

cs int N=1e5+7,M=N+N+1;

cs ll INF=1e12,I=-INF;

struct mat{
	ll a[4][4];int r,c;
	ll *operator[](int o){return a[o];}
	cs ll *operator[](int o)cs{return a[o];}
};

mat operator*(cs mat &A,cs mat &B){
	int r=A.r,m=A.c,c=B.c;
	assert(B.r==A.c);
	static mat C;C.r=r,C.c=c;
	for(int re i=0;i<r;++i)
		for(int re j=0;j<c;++j)
			C[i][j]=I; 
	for(int re i=0;i<r;++i)
		for(int re j=0;j<m;++j)if(A[i][j]>I)
		for(int re k=0;k<c;++k)
			cmax(C[i][k],A[i][j]+B[j][k]);
	return C;
}

struct Edge{int u,v,v0,v1;}E[M+N];

int n,m,rt;

void gmat(int u,mat &A){
	ll v0=E[u].v0,v1=E[u].v1;
	if(u<=n){
		A.r=2,A.c=1;A[0][0]=v0,A[1][0]=v1;
	}else {
		A.r=4,A.c=1;
		A[0][0]=A[3][0]=v0;
		A[1][0]=A[2][0]=v1;
	}
} 


namespace T{//Tree

cs int N=7e5+7;

int op[N],ch[N][3];
int sz[N],son[N],tg[N];
int el[N],nx[N];
void adde(int u,int v){
	nx[v]=el[u],el[u]=v;
}

int node(int o,int c1,int c2=0,int c3=0){
	int u=++rt;op[u]=o;
	if(c3){
		ch[u][2]=c3,adde(u,c3);sz[u]+=sz[c3];
		if(sz[son[u]]<sz[c3])son[u]=c3,tg[u]=3;
	}if(c2){
		ch[u][1]=c2,adde(u,c2);sz[u]+=sz[c2];
		if(sz[son[u]]<sz[c2])son[u]=c2,tg[u]=2;
	}if(c1){
		ch[u][0]=c1,adde(u,c1);sz[u]+=sz[c1];
		if(sz[son[u]]<sz[c1])son[u]=c1,tg[u]=1;
	}sz[u]++;return u;
}

int lsz[N],lc[N],rc[N],fa[N];
mat g[N],vl_son[N][2],prod[N];
int sm[N],st[N],tp,tg_son[N];

void calc_g(int u){
	mat &G=g[u];
	switch(op[u]){
		case 0:{gmat(u,G);break;}
		case 1:{
			auto &t=vl_son[u][0];
			ll a=t[0][0],b=t[1][0],c=t[2][0],d=t[3][0];
			G={a,I,I,I,I,b,I,I,I,I,c,I,I,I,I,d,4,4};
			break;
		}case 2:{
			G={0,I,I,I,I,I,0,I,I,0,I,I,I,I,I,0,4,4};
			break;
		}case 3:{
			switch(tg[u]){
				case 1:{
					auto &w=vl_son[u][0],&v=vl_son[u][1];
					G={
						w[0][0]+v[0][0],w[1][0]+v[2][0],I,I,
						w[0][0]+v[1][0],w[1][0]+v[3][0],I,I,
						I,I,w[0][0]+v[0][0],w[1][0]+v[2][0],
						I,I,w[0][0]+v[1][0],w[1][0]+v[3][0],4,4
					};
					break;
				}case 2:{
					auto &w=vl_son[u][0],&v=vl_son[u][1];
					G={
						w[0][0]+v[0][0],w[1][0]+v[2][0],I,I,
						w[0][0]+v[1][0],w[1][0]+v[3][0],I,I,
						w[2][0]+v[0][0],w[3][0]+v[2][0],I,I,
						w[2][0]+v[1][0],w[3][0]+v[3][0],I,I,4,2
					};
					break;
				}case 3:{
					auto &w=vl_son[u][0],&v=vl_son[u][1];
					G={
						w[0][0]+v[0][0],I,w[1][0]+v[1][0],I,
						I,w[0][0]+v[0][0],I,w[1][0]+v[1][0],
						w[2][0]+v[0][0],I,w[3][0]+v[1][0],I,
						I,w[2][0]+v[0][0],I,w[3][0]+v[1][0],4,4
					};
					break;
				}
			}break;
		}case 4:{
			switch(tg[u]){
				case 1:{
					auto &w=vl_son[u][0],&v=vl_son[u][1];
					G={
						w[0][0]+v[0][0],w[2][0]+v[0][0],I,I,
						w[1][0]+v[1][0],w[3][0]+v[1][0],I,I,
						I,I,I,I,I,I,I,I,2,2
					};
					break;
				}case 2:{
					auto &w=vl_son[u][0],&v=vl_son[u][1];
					G={
						w[0][0]+v[0][0],I,w[1][0]+v[0][0],I,
						I,w[0][0]+v[1][0],I,w[1][0]+v[1][0],
						I,I,I,I,I,I,I,I,2,4
					};
					break;
				}case 3:{
					auto &w=vl_son[u][0],&v=vl_son[u][1];
					G={
						std::max(w[0][0]+v[0][0],w[1][0]+v[2][0]),I,I,I,
						I,std::max(w[0][0]+v[1][0],w[1][0]+v[3][0]),I,I,
						I,I,I,I,I,I,I,I,2,2
					};
					break;
				}
			}break;
		}
	}
}

void pushup(int u){
	prod[u]=g[u];
	if(lc[u])prod[u]=prod[lc[u]]*prod[u];
	if(rc[u])prod[u]=prod[u]*prod[rc[u]];
}

int subbuild(int l,int r){
	if(l==r){calc_g(st[l]),pushup(st[l]);return st[l];}if(l>r)return 0;
	int m=std::lower_bound(sm+l,sm+r+1,(sm[l]+sm[r])>>1)-sm;
	int u=st[m];lc[u]=subbuild(l,m-1),rc[u]=subbuild(m+1,r);
	fa[lc[u]]=fa[rc[u]]=u,calc_g(u),pushup(u);return u;
}
int build(int u){
	for(int re p=u;p;p=son[p])
		lsz[p]=sz[p]-sz[son[p]];
	for(int re p=u;p;p=son[p]){int cso=0;
		for(int re w=el[p];w;w=nx[w])if(!lsz[w]){
			int v=build(w);tg_son[v]=cso;
			fa[v]=p,vl_son[p][cso++]=prod[v];
		}
	}tp=0;for(int re p=u;p;p=son[p])
		st[++tp]=p,sm[tp]=sm[tp-1]+lsz[p];
	return subbuild(1,tp);
}

void work(){
	rt=build(rt);int Q=gi();
	print(std::max(prod[rt][0][0],prod[rt][1][0]),'\n');
	while(Q--){
		int u=gi(),v0=gi(),v1=gi();
		E[u].v0=v0,E[u].v1=v1;calc_g(u);
		while(u){
			pushup(u);
			if(fa[u]&&(lc[fa[u]]!=u&&rc[fa[u]]!=u))
				vl_son[fa[u]][tg_son[u]]=prod[u],calc_g(fa[u]);
			u=fa[u];
		}print(std::max(prod[rt][0][0],prod[rt][1][0]),'\n');
	}
}

}

namespace G{//Graph

int id[N],d[N],vs[N];
std::unordered_map<int,int> eid[N];

void init(){
	for(int re i=1;i<=n;++i)id[i]=i;
	for(int re i=1;i<=rt;++i)T::sz[i]=1;
	for(int re i=1;i<=m;++i){
		int u=E[i+n].u,v=E[i+n].v;
		eid[u][v]=i+n,eid[v][u]=-i-n;
		++d[u],++d[v];
	}std::queue<int> q;
	for(int i=1;i<=n;++i)
		if(d[i]<=2)q.push(i),vs[i]=true;
	while(!q.empty()){
		int u=q.front();q.pop();
		switch(d[u]){
			case 1:{
				auto t=eid[u].begin();int v=t->fi,e=t->se;
				eid[u].clear();eid[v].erase(u);--d[v];
				if(e>0)id[v]=T::node(4,id[u],e,id[v]);
				else id[v]=T::node(4,id[u],T::node(2,-e),id[v]);
				if(!vs[v]&&d[v]<=2)q.push(v),vs[v]=true;
				break;
			}
			case 2:{
				int w=u,v,eu,ev,e;
				auto t=eid[w].begin();
				u=t->fi,eu=t->se;++t;
				v=t->fi,ev=t->se;eid[w].clear();
				eid[u].erase(w),eid[v].erase(w);
				if((ev>0)!=(eu<0)){
					if(ev<0)ev=T::node(2,-ev);
					else eu=-T::node(2,eu);
				}if(eu>0)std::swap(u,v),std::swap(eu,ev);
				e=T::node(3,-eu,id[w],ev);
				if(eid[u][v]){
					--d[u],--d[v];
					int et=eid[u][v];
					if(et<0)et=T::node(2,-et);
					e=T::node(1,e,et);
				}eid[u][v]=e,eid[v][u]=-e;
				if(!vs[u]&&d[u]<=2)q.push(u),vs[u]=true;
				if(!vs[v]&&d[v]<=2)q.push(v),vs[v]=true;
				break;
			}
		}
	}
} 

}

void Main(){
	n=gi(),m=gi();rt=n+m;
	for(int re i=1;i<=n;++i){
		int w=gi(),s=gi();
		E[i]={0,0,w,s};
	}for(int re i=1;i<=m;++i){
		int u=gi(),v=gi(),c=gi(),d=gi();
		E[i+n]={u,v,c,d};
	}G::init();T::work();
}

inline void file(){
#ifdef zxyoi
	freopen("park.in","r",stdin);
#endif
}signed main(){file();Main();return 0;}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章