zoukankan      html  css  js  c++  java
  • LOJ3044. 「ZJOI2019」Minimax 搜索

    LOJ3044. 「ZJOI2019」Minimax 搜索

    https://loj.ac/problem/3044

    分析:

    • 假设(w(1)=W),那么使得这个值变化只会有两三种可能,比(W)小的值变成(W+1),比(W)大的值变成(W-1),或直接修改(W)
    • 先考虑第一部分,设(f_{x})表示只改变权值(<W)的节点,(x)节点权值(le W)的概率,这样能推出(dp)式子
    • (f_x=prodlimits_{t}f_t​) ((dep_x is odd)​)
    • (f_x=1-prodlimits_{t}(1-f_t)​) ((dep_x is even)​)
    • 手动展开可以发现(f'_x=prodlimits_{t}(1-f'_x)​) ((f'_x=(-1)^{dep_x+1}f_x)​)
    • 对于另一个,我们设(g_x)表示只改变(>W)的点,(x)节点权值(<W)的概率,这样使得两个转移方程相同。
    • 然后对于不同的(K)可以看做是对两个节点的修改,动态(dp)即可。

    (f_x=prodlimits_{tin child_x}(1-f_t)​)

    (g_x=prodlimits_{tin child_x,t ot =s}(1-f_t)) (s)(x)的重儿子

    那么(f_x=(1-f_s) imes g_x)

    (=g_x-f_s imes g_x)
    (left[ egin{matrix}-g_x&g_x\0&1end{matrix} ight] imes left[egin{matrix}f_s\1end{matrix} ight]=left[egin{matrix}f_x\1end{matrix} ight])

    容易发现矩阵只需要存左上和右上,用两个变量维护即可。

    这里可能需要除(0​),需要记录一下非(0​)部分和(0​)的数量。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #include <iostream>
    using namespace std;
    #define N 200050
    #define mod 998244353
    #define ls ch[p][0]
    #define rs ch[p][1]
    #define db(x) cerr<<#x<<" = "<<x<<endl
    const int inv2=(mod+1)/2;
    typedef long long ll;
    int head[N],to[N<<1],nxt[N<<1],cnt,n,du[N],dep[N],fa[N],L,R,w[N];
    int siz[N],lf[N],son[N],sz[N],top[N],val[N],S[N];
    ll ans[N],mi[N];
    ll qp(ll x,ll y=mod-2) {
    	ll re=1;for(;y;y>>=1,x=x*x%mod) if(y&1) re=re*x%mod; return re;
    }
    inline void add(int u,int v) {
    	to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
    }
    void df1(int x,int y) {
    	int i;
    	siz[x]=lf[x];
    	fa[x]=y;
    	sz[x]=1;
    	dep[x]=dep[y]+1;
    	if(dep[x]&1) w[x]=0;
    	else w[x]=n;
    	for(i=head[x];i;i=nxt[i]) if(to[i]!=y) {
    		df1(to[i],x);
    		siz[x]+=siz[to[i]];
    		sz[x]+=sz[to[i]];
    		if(dep[x]&1) w[x]=max(w[x],w[to[i]]);
    		else w[x]=min(w[x],w[to[i]]);
    		if(sz[to[i]]>sz[son[x]]) son[x]=to[i];
    	}
    	if(lf[x]) w[x]=x;
    	val[x]=sz[x]-sz[son[x]];
    }
    struct A {
    	ll x; int t;
    	A() {x=0,t=0;}
    	A(ll x_,int t_) {x=x_,t=t_;}
    	void operator *= (const ll &u) {
    		if(!u) t++;
    		else x=x*u%mod;
    	}
    	void operator /= (const ll &u) {
    		if(!u) t--;
    		else x=x*qp(u)%mod;
    	}
    	operator ll() {return t?0:x;}
    };
    struct Mat {
    	ll l,r;
    	Mat() {}
    	Mat(ll l_,ll r_) {l=l_,r=r_;}
    	Mat operator * (const Mat &u) const {
    		return Mat(l*u.l%mod,(l*u.r+r)%mod);
    	}
    }I;
    struct Tree {
    	int ch[N][2],f[N];
    	A dp[N]; Mat F[N];
    	int flg,rt;
    	bool isrt(int x) {return ch[f[x]][0]!=x&&ch[f[x]][1]!=x;}
    	void pushup(int p) {
    		F[p]=Mat(-dp[p],dp[p]);
    		if(ls) F[p]=F[ls]*F[p];
    		if(rs) F[p]=F[p]*F[rs];
    	}
    	int build(int l,int r) {
    		if(l>r) return 0;
    		int sum=0,i,p,x=0;
    		for(i=l;i<=r;i++) sum+=val[S[i]];
    		for(i=l;i<=r;i++) {
    			x+=val[S[i]];
    			if((x<<1)>=sum) break;
    		}
    		p=S[i];
    		ls=build(l,i-1),rs=build(i+1,r);
    		if(ls) f[ls]=p;
    		if(rs) f[rs]=p;
    		if(!son[p]) {
    			if(flg==0) dp[p].x=(p<w[1]);
    			else dp[p].x=1-(p>w[1]);
    			if(!(dep[p]&1)) dp[p].x=1-dp[p].x;
    		}
    		pushup(p);
    		return p;
    	}
    	int dfs(int rr) {
    		int t,i,x;
    		for(x=rr;x;x=son[x]) {
    			dp[x].x=1;
    			for(i=head[x];i;i=nxt[i]) if(to[i]!=fa[x]&&to[i]!=son[x]) {
    				t=dfs(to[i]);
    				f[t]=x;
    				dp[x]*=(1-F[t].r);
    			}
    		}
    		int tp=0;
    		for(x=rr;x;x=son[x]) S[++tp]=x;
    		return build(1,tp);
    	}
    	void init() {
    		F[0]=I;
    		rt=dfs(1);
    	}
    	void UPD(int p,ll x) {
    		//puts("FUCK");
    		dp[p]=A(x,0);
    		for(;p;p=f[p]) {
    			if(isrt(p)) dp[f[p]]/=(1-F[p].r);
    			pushup(p);
    			if(isrt(p)) dp[f[p]]*=(1-F[p].r);
    		}
    	}
    }T0,T1;
    int main() {
    	I.l=1,I.r=0;
    	scanf("%d%d%d",&n,&L,&R);
    	int i,x,y;
    	for(mi[0]=i=1;i<=n;i++) mi[i]=mi[i-1]*2%mod;
    	for(i=1;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x),du[x]++,du[y]++;
    	for(i=2;i<=n;i++) if(du[i]==1) lf[i]=1;
    	df1(1,0);
    	T0.flg=0,T1.flg=1,T0.init(),T1.init();
    	//for(i=1;i<=n;i++) db(T0.dp[i]);
    	for(i=1;i<n;i++) {
    		//printf("%lld %lld
    ",T0.F[T0.rt].r,T1.F[T1.rt].r);
    		x=w[1]+i-1;
    		if(x>w[1]&&x<=n&&lf[x]) T0.UPD(x,inv2);
    		x=w[1]-i+1;
    		if(x>0&&x<w[1]&&lf[x]) T1.UPD(x,inv2);
    		ll v1=1-T0.F[T0.rt].r,v2=T1.F[T1.rt].r;
    		ans[i]=(mi[siz[1]]-(mi[siz[1]-1])*(v1*v2%mod))%mod;
    	}
    	ans[n]=mi[siz[1]]-1;
    	for(i=R;i>=L;i--) {
    		ans[i]=(ans[i]-ans[i-1])%mod;
    	}
    	for(i=L;i<=R;i++) {
    		printf("%lld ",(ans[i]+mod)%mod);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Django使用manage.py test错误解决
    Notepad++的find result窗口恢复
    qrcode 配套 PIL 或者 Image + ImageDraw
    pymssql.OperationalError: (20017 问题解决
    ConfigParser使用:1.获取所有section为list,2.指定section具体值,并转换为dict
    selenium&Firefox不兼容问题:Message: Unable to find a matching set of capabilitie;Can't load the profile. Profile;Message: 'geckodriver' executable needs to be in PATH
    使用宏实现透视表部分功能,将AB列数据合并统计.
    反射
    类的多态
    封装
  • 原文地址:https://www.cnblogs.com/suika/p/10725476.html
Copyright © 2011-2022 走看看