zoukankan      html  css  js  c++  java
  • 洛谷P5281 [ZJOI2019] Minimax搜索

    设修改前根节点的权值为 (W),不难发现,一定存在一条从根到叶子的链,链上的每个点权值都为 (W),那么只要这条链上任意一点权值改变,根节点权值最后一定会改变。

    考虑一个叶子 (i),且 (w_i eq W),要想通过改变该点权值来让链上的点发生改变,该点必须满足以下一个情况:

    (w_i<W),且该点祖先和链的第一个交点的深度为奇数,这时将其改为 (W+1)

    (w_i > W),且该点祖先和链的第一个交点的深度为偶数,这时将其改为 (W-1)

    直接处理代价为 (k) 的情况不好处理,考虑求出代价 (leqslant k) 的方案后差分。

    将问题转化为概率来考虑,链上的点设 (f_x) 表示 (x) 子树内的叶子通过代价 (leqslant k) 的修改后 (x) 权值不变的概率,得最终方案数为总方案乘 (1-prod f_x)。考虑不在链上的点,若其深度为奇数,(DP) 值为权值 (<W) 的概率,若其深度为偶数,(DP) 值为权值 (>W) 的概率,得转移为:

    [large f_x=prod_{yin son_x}1-f_y ]

    这样做需要对每个 (k)(DP) 一遍,复杂度无法接受。因此将 (k) 也加到状态中,对所有 (k) 一起 (DP),用线段树合并实现整体 (DP) 即可。

    同时发现在枚举 (k) 的过程中,每个点是否要修改的情况只会改变一次,因此也能用动态 (DP) 来优化。

    暴力 (DP),有 (70) 分。

    #include<bits/stdc++.h>
    #define maxn 400010
    #define inf 1000000000
    #define p 998244353
    using namespace std;
    typedef long long ll;
    template<typename T> inline void read(T &x)
    {
    	x=0;char c=getchar();bool flag=false;
    	while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	if(flag)x=-x;
    }
    int n,L,R,k,pw=1;
    int dep[maxn],val[maxn],ans[maxn];
    ll f[maxn];
    struct edge
    {
    	int  to,nxt;
    	edge(int a=0,int b=0)
    	{
    		to=a,nxt=b;
    	}
    }e[maxn];
    int head[maxn],edge_cnt;
    void add(int from,int to)
    {
    	e[++edge_cnt]=edge(to,head[from]),head[from]=edge_cnt;
    }
    void dfs_pre(int x,int fa)
    {
    	val[x]=(dep[x]=dep[fa]+1)&1?-inf:inf;
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		int y=e[i].to;
    		if(y==fa) continue;
    		dfs_pre(y,x),val[x]=dep[x]&1?max(val[x],val[y]):min(val[x],val[y]);
    	}
    	if(abs(val[x])==inf) val[x]=x,pw=pw*2%p;
    }
    void dp(int x,int fa,int d)
    {
    	if(x==val[x])
    	{
    		if(abs(x-val[1])<k&&(d&1?x<val[1]:x>val[1])) f[x]=(p+1)>>1;
    		else f[x]=dep[x]&1?x<val[1]:x>val[1];
    		return;
    	}
    	f[x]=1;
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		int y=e[i].to;
    		if(y==fa) continue;
    		dp(y,x,d),f[x]=f[x]*(1-f[y]+p)%p;
    	}
    }
    void dfs(int x,int fa)
    {
    	f[x]=x==val[x]?(p+1)>>1:1;
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		int y=e[i].to;
    		if(y==fa) continue;
    		if(val[x]==val[y]) dfs(y,x),f[1]=f[1]*f[y]%p;
    		else dp(y,x,dep[x]),f[x]=f[x]*(1-f[y]+p)%p;
    	}
    }
    int main()
    {
    	read(n),read(L),read(R);
    	for(int i=1;i<n;++i)
    	{
    		int x,y;
    		read(x),read(y);
    		add(x,y),add(y,x);
    	}
    	dfs_pre(1,0);
    	for(int i=max(L-1,1);i<=R;++i)
    	{
    		k=i;
    		if(i==n) ans[i]=(pw-1+p)%p;
    		else dfs(1,0),ans[i]=(1-f[1]+p)*pw%p;
    		if(i>=L) printf("%d ",(ans[i]-ans[i-1]+p)%p);
    	}
    	return 0;
    }
    

    线段树合并,整体 (DP)

    #include<bits/stdc++.h>
    #define maxn 400010
    #define maxm 12000010
    #define inf 1000000000
    #define p 998244353
    #define mid ((l+r)>>1)
    using namespace std;
    typedef long long ll;
    template<typename T> inline void read(T &x)
    {
    	x=0;char c=getchar();bool flag=false;
    	while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	if(flag)x=-x;
    }
    int n,L,R,k,pw=1,tot;
    int dep[maxn],val[maxn],ans[maxn],rt[maxn],ls[maxm],rs[maxm],add[maxm],mul[maxm];
    struct edge
    {
    	int  to,nxt;
    	edge(int a=0,int b=0)
    	{
    		to=a,nxt=b;
    	}
    }e[maxn];
    int head[maxn],edge_cnt;
    void link(int from,int to)
    {
    	e[++edge_cnt]=edge(to,head[from]),head[from]=edge_cnt;
    }
    void dfs_pre(int x,int fa)
    {
    	val[x]=(dep[x]=dep[fa]+1)&1?-inf:inf;
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		int y=e[i].to;
    		if(y==fa) continue;
    		dfs_pre(y,x),val[x]=dep[x]&1?max(val[x],val[y]):min(val[x],val[y]);
    	}
    	if(abs(val[x])==inf) val[x]=x,pw=pw*2%p;
    }
    int get()
    {
    	mul[++tot]=1;
    	return tot;
    }
    void pushadd(int &x,int v)
    {
    	if(!x) x=get();
    	add[x]=(add[x]+v)%p;
    }
    void pushmul(int &x,int v)
    {
    	if(!x) x=get();
    	add[x]=(ll)add[x]*v%p,mul[x]=(ll)mul[x]*v%p;
    }
    void pushdown(int x)
    {
    	if(mul[x]!=1) pushmul(ls[x],mul[x]),pushmul(rs[x],mul[x]),mul[x]=1;
    	if(add[x]) pushadd(ls[x],add[x]),pushadd(rs[x],add[x]),add[x]=0;
    }
    void modify(int L,int R,int l,int r,int v,int &cur)
    {
    	if(!cur) cur=get();
    	if(L<=l&&R>=r)
    	{
    		pushadd(cur,v);
    		return;
    	}
    	pushdown(cur);
    	if(L<=mid) modify(L,R,l,mid,v,ls[cur]);
    	if(R>mid) modify(L,R,mid+1,r,v,rs[cur]);
    }
    int merge(int x,int y)
    {
    	if(!x&&!y) return 0;
    	if(!ls[y]&&!rs[y])
    	{
    		pushmul(x,add[y]);
    		return x;
    	}
    	if(!ls[x]&&!rs[x])
    	{
    		pushmul(y,add[x]);
    		return y;
    	}
    	pushdown(x),pushdown(y);
    	ls[x]=merge(ls[x],ls[y]),rs[x]=merge(rs[x],rs[y]);
    	return x;
    }
    void solve(int l,int r,int cur)
    {
    	if(!ls[cur]&&!rs[cur])
    	{
    		for(int i=l;i<=r;++i) ans[i]=(ll)(1-add[cur]+p)*pw%p;
    		return;
    	}
    	pushdown(cur),solve(l,mid,ls[cur]),solve(mid+1,r,rs[cur]);
    }
    void dp(int x,int fa,int d)
    {
    	if(x==val[x])
    	{
    		if(d&1?x<val[1]:x>val[1])
    			modify(1,abs(x-val[1]),1,n-1,dep[x]&1?x<val[1]:x>val[1],rt[x]),modify(abs(x-val[1])+1,n-1,1,n-1,(p+1)>>1,rt[x]);
    		else pushadd(rt[x],dep[x]&1?x<val[1]:x>val[1]);
    		return;
    	}
    	pushadd(rt[x],1);
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		int y=e[i].to;
    		if(y==fa) continue;
    		dp(y,x,d),pushmul(rt[y],p-1),pushadd(rt[y],1),rt[x]=merge(rt[x],rt[y]);
    	}
    }
    void dfs(int x,int fa)
    {
    	pushadd(rt[x],x==val[x]?(p+1)>>1:1);
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		int y=e[i].to;
    		if(y==fa) continue;
    		if(val[x]==val[y]) dfs(y,x),rt[1]=merge(rt[1],rt[y]);
    		else dp(y,x,dep[x]),pushmul(rt[y],p-1),pushadd(rt[y],1),rt[x]=merge(rt[x],rt[y]);
    	}
    }
    int main()
    {
    	read(n),read(L),read(R);
    	for(int i=1;i<n;++i)
    	{
    		int x,y;
    		read(x),read(y);
    		link(x,y),link(y,x);
    	}
    	dfs_pre(1,0),ans[n]=(pw-1+p)%p,dfs(1,0),solve(1,n-1,rt[1]);
    	for(int i=L;i<=R;++i) printf("%d ",(ans[i]-ans[i-1]+p)%p);
    	return 0;
    }
    
  • 相关阅读:
    卡牌配对
    SNOI2017 礼物
    【BZOJ2893】征服王
    景中人
    钦点
    杨柳
    兼容IE与firefox、chrome的css 线性渐变(linear-gradient)
    使用C# DES解密java DES加密的字符串
    jQuery插件autoComplete使用
    hadoop SQL使用
  • 原文地址:https://www.cnblogs.com/lhm-/p/14435988.html
Copyright © 2011-2022 走看看