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;
    }
    
    
  • 相关阅读:
    进程池,线程池,协程,gevent模块,协程实现单线程服务端与多线程客户端通信,IO模型
    线程相关 GIL queue event 死锁与递归锁 信号量l
    生产者消费者模型 线程相关
    进程的开启方式 进程的join方法 进程间的内存隔离 其他相关方法 守护进程 互斥锁
    udp协议 及相关 利用tcp上传文件 socketserver服务
    socket套接字 tcp协议下的粘包处理
    常用模块的完善 random shutil shevle 三流 logging
    day 29 元类
    Django入门
    MySQL多表查询
  • 原文地址:https://www.cnblogs.com/suika/p/10725476.html
Copyright © 2011-2022 走看看