20260120模拟赛

20260120模拟赛

白点黑点

考虑对于一个度数序列能造出那些最大匹配,如果造出的最大匹配最大是 \(r\),最小是 \(l\),则 \([l,r]\) 之间的都能取到。

\(r\) 是好求的,即两边度数不为 \(0\) 的点的个数取 \(\min\)\(l\) 不好求,考虑 Hall 定理,最大匹配为 \(n+\min_{S}(|N(S)|-|S|)\)。由于取值连续且答案取 \(\min\),所以我们只要考虑了所有的 \(n+|N(S)|-|S|\),答案就是对的。

\(f_{i,j,s,k,t}\) 表示前 \(i\) 个点,\(j\) 个进入 \(S\) 中,\(S\) 中度数为 \(s\),度数不为 \(0\) 的点有 \(k\) 个,总度数为 \(t\),的最小值。转移时枚举当前点的度数是多少。

对左右两边分别做上述 DP,记为 \(f,g\),然后合并。合并时枚举左右度数不为 \(0\) 的点有多少,枚举所有 \(S\)\(N(S)\),考虑了所有的答案就是对的。

代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;

inline ll read(){
	ll s=0,k=1;
	char c=getchar();
	while(c>'9'||c<'0'){
		if(c=='-') k=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		s=(s<<3)+(s<<1)+(c^48);
		c=getchar();
	}
	return s*k;
}

const int N=32;
const ll inf=1e18+7;
int n,m;
ll a[N][N],b[N][N];
ll f[N][N][N][N][N],g[N][N][N][N][N],ans[N];

void cmin(ll &x,ll y){x=min(x,y);}

void solve(ll a[N][N],ll f[N][N][N][N][N]){
	memset(f,0x3f,sizeof(g));
	f[0][0][0][0][0]=0;
	for(int i=0;i<n;i++)
		for(int j=i;j>=0;j--)
			for(int s=m;s>=0;s--)
				for(int k=i;k>=0;k--)
					for(int t=m;t>=s;t--){
						ll val=f[i][j][s][k][t];
						for(int d=0;d+t<=m;d++){
							cmin(f[i+1][j+1][s+d][k+(d>0)][t+d],val+a[i][d]);
							cmin(f[i+1][j][s][k+(d>0)][t+d],val+a[i][d]);
						}
					}
}

int main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n=read();m=read();
	for(int i=0;i<n;i++)
		for(int j=0;j<=m;j++) a[i][j]=read();
	for(int i=0;i<n;i++)
		for(int j=0;j<=m;j++) b[i][j]=read();
	solve(a,f); solve(b,g);
//	for(int i=1;i<=n;i++)
//	for(int j=0;j<=n;j++)
//		for(int s=0;s<=m;s++)
//			for(int k=0;k<=n;k++)
//				for(int t=0;t<=m;t++) cout<<(f[i][j][s][k][t]<inf/2?f[i][j][s][k][t]:-1)<<' ';
	for(int i=0;i<=n;i++) ans[i]=inf;
	for(int j=0;j<=n;j++)
		for(int s=0;s<=m;s++)
			for(int k=0;k<=n;k++)
				for(int t=s;t<=m;t++){
					ll mn=inf;
					int L=n+k-j;
					for(int R=n;R>=L;R--)
						for(int i=R;i<=n;i++){
							mn=min({mn,f[n][j][s][R][m]+g[n][k][t][i][m],f[n][j][s][i][m]+g[n][k][t][R][m]});
							ans[R]=min(ans[R],mn);
						}
				}
	for(int i=0;i<=n;i++){
//		cout<<ans[i]<<' '<<inf/2<<endl;
		if(ans[i]>inf/2) printf("no ");
		else printf("%lld ",ans[i]);
	}
	return 0;
}

动物园大会

考虑每条路径的贡献,\(op=1\) 时相当于它父亲每个删去了一个,删去一个点影响的贡献分为这个点与上方所有父亲之间的逆序对,以及对其子树内所有点的逆序对。这两部分都可以三维偏序计算。\(op=1\) 的影响就是其所有父亲影响的前缀和,可以预处理。

\(op=2\) 时先做两边 \(op=1\),然后考虑加上减重的贡献。还是对于每条路径考虑,如果连个点在这条路径上是同一种值则没有算错。否则设两种值删点之后还剩 \(a,b\) 个,原来贡献是 \((a+1)(b+1)\),现在是 \(ab\),我们删去了 \((a+1)+(b+1)\),多删了一个 \(1\),所以对于 \(u\to lca\)\(v\to lca\) 上的点及其子树再计算这个 \(1\) 总和是多少,这可以离线询问差分后三维偏序计算。

代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;

inline int read(){
	int s=0,k=1;
	char c=getchar();
	while(c>'9'||c<'0'){
		if(c=='-') k=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		s=(s<<3)+(s<<1)+(c^48);
		c=getchar();
	}
	return s*k;
}

const int N=150005;
int cnt,a[N],b[N],siz[N],n,Q,fat[N],dfn[N*4],low[N*4],dep[N];
ll c[N],disw[N],w[N],disp[N],p[N],sum[N],rev[N],ans[N];
struct que{
	int op,x,y;ll z;
}qu[N*5];
vector<int>e[N];
vector<pair<int,int> >vec[N];

void add(int x,ll v){
	while(x<=n){
		c[x]+=v;
		x+=x&-x;
	}
}

ll query(int x){
	ll ans=0;
	while(x>0){
		ans+=c[x];
		x-=x&-x;
	}
	return ans;
}

void cdq(int l,int r){
	if(l==r) return ;
	int mid=l+r>>1;
	cdq(l,mid);cdq(mid+1,r);
	int i=l,j=mid+1,k=l,x=dfn[i],y=dfn[j];
	while(i<=mid&&j<=r){
		if(qu[x].x<qu[y].x){
			if(qu[x].op==1) add(qu[x].y,qu[x].z);
			low[k++]=x;i++;x=dfn[i];
		}
		else{
			if(qu[y].op==2){
				int v=qu[y].z;
				if(v<0){
					v=-v;
					rev[v]-=query(n)-query(qu[y].y)-query(qu[y].y-1);
				}
				else{
					rev[v]+=query(n)-query(qu[y].y)-query(qu[y].y-1);
				}
			}
			low[k++]=y;j++;y=dfn[j];
		}
	}
	while(i<=mid){
		if(qu[x].op==1) add(qu[x].y,qu[x].z);
		low[k++]=x; i++; x=dfn[i];
	}
	while(j<=r){
		if(qu[y].op==2){
			int v=qu[y].z;
			if(v<0){
				v=-v;
				rev[v]-=query(n)-query(qu[y].y)-query(qu[y].y-1);
			}
			else{
				rev[v]+=query(n)-query(qu[y].y)-query(qu[y].y-1);
			}
		}
		low[k++]=y; j++; y=dfn[j];
	}
	for(int i=mid+1;i<=r;i++){
		int y=dfn[i];
		if(qu[y].op==2){
			int v=qu[y].z;
			if(v<0){
				v=-v;
				rev[v]-=query(qu[y].y-1);
			}
			else{
				rev[v]+=query(qu[y].y-1);
			}
		}
	}
	for(int i=l;i<=mid;i++) {
		int x=dfn[i];
		if(qu[x].op==1) add(qu[x].y,-qu[x].z);
	}
	for(int i=l;i<=r;i++) dfn[i]=low[i];
}

namespace sub1{
	void dfz(int x,int fa){
		dep[x]=dep[fa]+1;
		siz[x]=1;
		for(int v:e[x]){
			if(v==fa) continue;
			fat[v]=x;
			dfz(v,x);
			siz[x]+=siz[v];
		}
	}
	
	void dfs(int x,int fa){
		if(siz[x]-1) qu[++cnt]={1,a[x],b[x],siz[x]-1};
		qu[++cnt]={2,a[x],b[x],x};
		ll s=siz[x]-1;
		for(int v:e[x]){
			if(v==fa) continue;
			if(siz[x]-siz[v]-s) qu[++cnt]={1,a[x],b[x],siz[x]-siz[v]-s};
			s=siz[x]-siz[v];
			dfs(v,x);
		}
		if(-s) qu[++cnt]={1,a[x],b[x],-s};
	}
	
	void dfp(int x,int fa,ll val){
		disw[x]=val+w[x]*(siz[x]-1);
		for(int v:e[x])	
			if(v!=fa) dfp(v,x,val+w[x]*(siz[x]-siz[v]));
	}
	
	void solve(){
		dfz(1,0);
		dfs(1,0);
		for(int i=1;i<=n;i++) rev[i]=0;
		for(int i=1;i<=cnt;i++) dfn[i]=i;
		cdq(1,cnt);
		for(int i=1;i<=n;i++) w[i]=rev[i];
		dfp(1,0,0);
	}
}

namespace sub2{
	void dfs(int x,int fa){
		if(fa) qu[++cnt]={2,a[fa],b[fa],-x};
		ll sum=1;
		for(int v:e[x]) if(v!=fa) sum+=1ll*siz[v]*siz[v];
		if(1ll*siz[x]*siz[x]-sum) qu[++cnt]={1,a[x],b[x],1ll*siz[x]*siz[x]-sum};
		for(int v:e[x]){
			if(v==fa) continue;
			dfs(v,x);
		}
		if(fa) qu[++cnt]={2,a[fa],b[fa],x};
	}
	
	void dfz(int x,int fa,ll w){
		disp[x]=w+sum[x];
		for(int v:e[x])
			if(v!=fa) dfz(v,x,w+sum[x]-p[v]);
	}
	
	void solve(){
		cnt=0; dfs(1,0);
		for(int i=1;i<=n;i++) rev[i]=0;
		for(int i=1;i<=cnt;i++) dfn[i]=i;
		cdq(1,cnt);
		for(int i=1;i<=n;i++) p[i]=rev[i];
		for(int x=1;x<=n;x++)
			for(int v:e[x]) if(v!=fat[x]) sum[x]+=p[v];
		dfz(1,0,0);
	}
}

namespace sub3{
	void dfs(int x,int fa){
		for(auto o:vec[x])
			if(o.first<0){
				int i,v;tie(i,v)=o;
				qu[++cnt]={2,a[v],b[v],i};
			}
		if(siz[x]-1) qu[++cnt]={1,a[x],b[x],siz[x]-1};
		ll s=siz[x]-1;
		for(int v:e[x]){
			if(v==fa) continue;
			if(siz[x]-siz[v]-s) qu[++cnt]={1,a[x],b[x],siz[x]-siz[v]-s};
			s=siz[x]-siz[v];
			dfs(v,x);
		}
		if(-s) qu[++cnt]={1,a[x],b[x],-s};
	}
	
	void dfz(int x,int fa){
		if(siz[x]-1) qu[++cnt]={1,a[x],b[x],siz[x]-1};
		for(auto o:vec[x])
			if(o.first>0){
				int i,v;tie(i,v)=o;
				qu[++cnt]={2,a[v],b[v],i};
			}
		ll s=siz[x]-1;
		for(int v:e[x]){
			if(v==fa) continue;
			if(siz[x]-siz[v]-s) qu[++cnt]={1,a[x],b[x],siz[x]-siz[v]-s};
			s=siz[x]-siz[v];
			dfz(v,x);
		}
		if(-s) qu[++cnt]={1,a[x],b[x],-s};
	}
	
	void solve(){
		cnt=0; dfs(1,0);
		for(int i=1;i<=Q;i++) rev[i]=0;
		for(int i=1;i<=cnt;i++) dfn[i]=i;
		cdq(1,cnt);
		for(int i=1;i<=Q;i++) ans[i]+=rev[i];
		cnt=0; dfz(1,0);
		for(int i=1;i<=Q;i++) rev[i]=0;
		for(int i=1;i<=cnt;i++) dfn[i]=i;
		cdq(1,cnt);
		for(int i=1;i<=Q;i++) ans[i]+=rev[i]*2;
	}
}

namespace LCAF{
	int fa[22][N],lgn[N];
	
	int jump(int x,int k){
		for(int i=lgn[k];i>=0;i--)
			if(k>>i&1) x=fa[i][x];
		return x;
	}
	
	int LCA(int x,int y){
		if(dep[x]>dep[y]) swap(x,y);
		for(int i=lgn[dep[y]];i>=0;i--)
			if(dep[fa[i][y]]>=dep[x]) y=fa[i][y];
		if(x==y) return x;
		for(int i=lgn[dep[x]];i>=0;i--)
			if(fa[i][x]!=fa[i][y]){
				x=fa[i][x];
				y=fa[i][y];
			}
		return fa[0][x];
	}
	
	void init(){
		for(int i=2;i<=n;i++) lgn[i]=lgn[i>>1]+1;
		for(int i=1;i<=n;i++) fa[0][i]=fat[i];
		for(int j=1;j<=lgn[n];j++)
			for(int i=1;i<=n;i++) fa[j][i]=fa[j-1][fa[j-1][i]];
	}
}
using LCAF::LCA;
using LCAF::jump;

int main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n=read();Q=read();
	for(int i=1;i<=n;i++){
		a[i]=read();
		b[i]=read();
	}
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		e[u].push_back(v);
		e[v].push_back(u);
	}
	sub1::solve();
	ll rse=0;
	for(int i=1;i<=n;i++) rse+=disw[i];
	printf("%lld\n",rse);
	if(Q==0) return 0;
	LCAF::init();
	sub2::solve();
	for(int i=1;i<=Q;i++){
		int op=read();
		if(op==1){
			int x=read();
			ans[i]=rse-2*disw[x]-disp[x];	
		}
		else{
			int x=read(),y=read();
			int lca=LCA(x,y);
			ans[i]=rse-2*disw[x]-disp[x]-2*disw[y]-disp[y];
			if(lca==y) swap(x,y);
			if(lca==x){
				int v=jump(y,dep[y]-dep[lca]-1);
				ans[i]+=w[lca];
				vec[v].push_back({-i,lca});
				vec[y].push_back({i,lca});
			}
			else{
				int u=jump(x,dep[x]-dep[lca]-1);
				int v=jump(y,dep[y]-dep[lca]-1);
				vec[u].push_back({-i,lca});
				vec[v].push_back({-i,lca});
				vec[x].push_back({i,lca});
				vec[y].push_back({i,lca});
			}
		}
	}
	sub3::solve();
	for(int i=1;i<=Q;i++) printf("%lld\n",ans[i]);
	return 0;
}
### 
posted @ 2026-01-23 11:41  programmingysx  阅读(4)  评论(0)    收藏  举报
Title