20240724【省选】模拟

挂了四分,掉了一名,不过这也说明我的实力就只有这点,根本不够,果然以后还是直接【数据删除】得了。

T1

其实就是个树剖,每个点维护左右子树的最大深度以及左右子树内的最大答案,然后就…………没了?

淦,也是实现问题,应该想到的。然后就是修改边权是改成 wapai 是记录下来的 i 的父边边权。

真没了

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll int
#define ls now<<1
#define rs now<<1|1
const ll N=2*114514,M=1919810;
struct xx{
	ll next,to;
}e[2*N];
ll head[2*N],cnt;
void add(ll x,ll y){
	e[++cnt].next=head[x];
	e[cnt].to=y;
	head[x]=cnt;
}
ll n,m,fr[N];
ll in[N],out[N],t_cnt;
void dfs(ll u,ll fa){
	in[u]=out[u]=++t_cnt;
	for(int i=head[u];i;i=e[i].next){
		ll v=e[i].to;
		if(v==fa) continue;
		dfs(v,u);
		out[u]=++t_cnt;
	}
}
struct tree{
	ll res,tag;
	ll mx,mn,lmx,rmx;
}t[4*N];
void modify(ll now,ll k){
	t[now].mx+=k,t[now].mn+=k;
	t[now].lmx-=k,t[now].rmx-=k;
	t[now].tag+=k;
}
void pushup(ll now){
	t[now].mx=max(t[ls].mx,t[rs].mx),t[now].mn=min(t[ls].mn,t[rs].mn);
	t[now].lmx=max(max(t[ls].lmx,t[rs].lmx),t[ls].mx-2*t[rs].mn);
	t[now].rmx=max(max(t[ls].rmx,t[rs].rmx),t[rs].mx-2*t[ls].mn);
	t[now].res=max(t[ls].res,t[rs].res);
	t[now].res=max(t[now].res,max(t[ls].mx+t[rs].rmx,t[rs].mx+t[ls].lmx));
}
void pushdown(ll now){
	ll k=t[now].tag;
	if(!k) return;
	modify(ls,k),modify(rs,k);
	t[now].tag=0;
}
void build(ll now,ll l,ll r){
	if(l==r){
		t[now].lmx=t[now].rmx=t[now].res=-1;
		return;
	}
	ll mid=(l+r)>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	pushup(now);
}
void update(ll now,ll l,ll r,ll x,ll y,ll k){
	if(l>=x&&r<=y){
		modify(now,k);
		return;
	}
	pushdown(now);
	ll mid=(l+r)>>1;
	if(x<=mid) update(ls,l,mid,x,y,k);
	if(y>mid) update(rs,mid+1,r,x,y,k);
	pushup(now);
}
ll p,w,a[N];
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin>>n>>m;
	for(int i=2;i<=n;++i){
		cin>>fr[i];
		add(i,fr[i]),add(fr[i],i);
	}
	build(1,1,n);
	dfs(1,0);
	for(int i=1;i<=m;++i){
		cin>>p>>w;
		update(1,1,t_cnt,in[p],out[p],w-a[p]);
		a[p]=w;
		cout<<t[1].res<<'\n';
	}
	return 0;
}/*5 4
1 1 2 2
4 8
4 3
2 2
5 7
拥有蒟蒻的力量,退役是必然的*/

T2

知道是个 dp,状态设出来了,推不出来,太菜了

dp[u][i][j][k] 表示在 u 的子树中选 u 并总共选了 i 个🐂,j 个🐏,k 个小C时的方案数。因为 A+B+Cn2,所以对于 n50 的数据直接 O(n(ABC)2) 暴力 dp 就行了。

正解考虑树形依赖背包,通过我和想到的非常接近的 dp 可以做到 O(nABC),但是这样只能算包含根结点的连通块数,于是考虑套个点分治解决,复杂度 O(nABClogn),点分治是我没想到的/ng

需要注意的是,dp 数组直接开 dp[201][201][201][201] 是要爆的,但是 A+B+Cn2,所以可以考虑把后三维压缩成一维,能存下。

不过为啥严队代码是最裂解啊

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll int
const ll N=205,M=55,mod=998244353;
ll cf[N][N];
struct xx{
	ll next,to;
}e[2*N];
ll head[2*N],cnt;
void add(ll x,ll y){
	e[++cnt].next=head[x];
	e[cnt].to=y;
	head[x]=cnt;
}
ll n,A,B,C,col[N],siz[N],ans;
ll dp[N][43999],vis[N],mx,rt,mxz; //米学长(雾 
void findrt(ll u,ll fa){
	siz[u]=1;
	ll maxn=0;
	for(int i=head[u];i;i=e[i].next){
		ll v=e[i].to;
		if(v==fa||vis[v]) continue;
		findrt(v,u);
		siz[u]+=siz[v];
		maxn=max(maxn,siz[v]);
	}
	maxn=max(maxn,mxz-siz[u]);
	if(mx>maxn) mx=maxn,rt=u;
}
ll dfn[N],t_cnt,c[N],sz[N];
void dfs(ll u,ll fa){
	dfn[u]=++t_cnt;
	c[t_cnt]=col[u];
	sz[dfn[u]]=1;
	for(int i=head[u];i;i=e[i].next){
		ll v=e[i].to;
		if(v==fa||vis[v]) continue;
		dfs(v,u);
		sz[dfn[u]]+=sz[dfn[v]];
	}
}
ll &f(ll u,ll i,ll j,ll k){
	return dp[u][i*(B+1)*(C+1)+j*(C+1)+k];
}
void solve(ll u){
	memset(dp,0,sizeof(dp));
	t_cnt=0,dfs(u,0);
	f(1,0,0,0)=1;
	for(int i=1;i<=t_cnt;++i)
		for(int x=0;x<=A;++x)
			for(int y=0;y<=B;++y)
				for(int z=0;z<=C;++z){
					ll val=f(i,x,y,z);
					if(!val) continue;
					if(c[i]==0&&x<A) (f(i+1,x+1,y,z)+=val)%=mod;
					if(c[i]==1&&y<B) (f(i+1,x,y+1,z)+=val)%=mod;
					if(c[i]==2&&z<C) (f(i+1,x,y,z+1)+=val)%=mod;
					(f(i+sz[i],x,y,z)+=val)%=mod;
				}
	for(int x=0;x<=A;++x)
		for(int y=0;y<=B;++y)
			for(int z=0;z<=C;++z)
				(ans+=f(t_cnt+1,x,y,z))%=mod;
	--ans;
}
void calc(ll u){
	vis[u]=1;
	solve(u);
	ll xxs=mxz;
	for(int i=head[u];i;i=e[i].next){
		ll v=e[i].to;
		if(vis[v]) continue;
		mxz=siz[u]>siz[v]?siz[v]:xxs-siz[u];
		mx=1919810;
		findrt(v,u),calc(rt); 
	}
}
int main(){
	//freopen("b.in","r",stdin);
	//freopen("b.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin>>n>>A>>B>>C;
	for(int i=1;i<=n;++i) cin>>col[i];
	for(int i=1;i<n;++i){
		ll a,b;
		cin>>a>>b;
		add(a,b),add(b,a);
	}
	mxz=n,mx=1919810;
	findrt(1,0),calc(rt);
	cout<<ans;
	return 0;
}/*5 1 1 1
0 1 0 0 2
1 2
1 3
3 4
4 5
拥有蒟蒻的力量,退役是必然的*/

T3

xrq 场切,○| ̄|_ 不过讲过我也做不来,赛时只有大众分/ll

posted @   和蜀玩  阅读(25)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示