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=\prod\limits_{t}f_t​\) \((dep_x\ is \ odd)​\)
  • \(f_x=1-\prod\limits_{t}(1-f_t)​\) \((dep_x\ is\ even)​\)
  • 手动展开可以发现\(f'_x=\prod\limits_{t}(1-f'_x)​\) \((f'_x=(-1)^{dep_x+1}f_x)​\)
  • 对于另一个,我们设\(g_x\)表示只改变\(>W\)的点,\(x\)节点权值\(<W\)的概率,这样使得两个转移方程相同。
  • 然后对于不同的\(K\)可以看做是对两个节点的修改,动态\(dp\)即可。

\(f_x=\prod\limits_{t\in child_x}(1-f_t)​\)

\(g_x=\prod\limits_{t\in child_x,t\not =s}(1-f_t)\) \(s\)\(x\)的重儿子

那么\(f_x=(1-f_s)\times g_x\)

\(=g_x-f_s\times g_x\)
\(\left[ \begin{matrix}-g_x&g_x\\0&1\end{matrix}\right]\times \left[\begin{matrix}f_s\\1\end{matrix}\right]=\left[\begin{matrix}f_x\\1\end{matrix}\right]\)

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

这里可能需要除\(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\n",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;
}

posted @ 2019-04-17 18:49  fcwww  阅读(834)  评论(0编辑  收藏  举报