题解 P5281 【[ZJOI2019]Minimax搜索】
直接求
设
在整棵树上,满足
考虑每个叶子
因此,如果当前代价为
将链上的边断掉,可以对每个联通块求解有多少种方案会使得子树中存在的权值
计算
设
至此,枚举最大代价的限制
注意到将
重链剖分之后,有:
可以发现这是一个
在每次跳轻边的时候,都需要一次求逆,因此哪怕你写了全局平衡二叉树,复杂度依旧会达到
维护轻儿子的积时,因为可能出现乘
```cpp
#include<bits/stdc++.h>
using namespace std;
#define lc ls[p]
#define rc rs[p]
#define I inline int
#define V inline void
#define ll long long int
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define ROF(i,a,b) for(int i=a;i>=b;i--)
#define REP(u) for(int i=h[u],v;v=e[i].t;i=e[i].n)if(v!=pre[u])
const int N=2e5+1,mod=998244353,INF=0x3f3f3f3f,sgn[2]={-1,1};
V cmin(int&x,int y){if(y-x>>31)x=y;}
V cmax(int&x,int y){if(x-y>>31)x=y;}
V check(int&x){x-=mod,x+=x>>31&mod;}
int sum[N],zero[N];
int n,m,L,R,W,tot,qwq,bas=1;
int h[N],dep[N],dp[N],ans[N],co[N];
int siz[N],wes[N],tmp[N],pre[N],cnt[N];
int ls[N],rs[N],fa[N],id[N],top[N],d[N];
struct node{
int b,c;
node(int x=0,int y=1){b=x,c=y;}
node operator+(const node&u)const{
return(node){int((1ll*c*u.b+b)%mod),int(1ll*c*u.c%mod)};
}
}a[N],t[N];
struct edge{int t,n;}e[N<<1];
V add_edge(int x,int y){
e[++tot]=(edge){y,h[x]},h[x]=tot,d[x]++;
e[++tot]=(edge){x,h[y]},h[y]=tot,d[y]++;
}
I Pow(ll t,int x,ll s=1){for(;x;x>>=1,t=t*t%mod)if(x&1)s=s*t%mod;return s;}
V input(){
scanf("%d%d%d",&n,&L,&R);int x,y;
FOR(i,2,n)scanf("%d%d",&x,&y),add_edge(x,y);
}
I leaf(int u){return u>1&&d[u]==1;}
V dfs0(int u){
dp[u]=(~dep[u]&1)*INF;
REP(u)dep[v]=dep[u]+1,pre[v]=u,dfs0(v),(dep[u]&1?cmax:cmin)(dp[u],dp[v]);
if(leaf(u))dp[u]=u;
}
V dfs1(int u){
siz[u]=1,cnt[u]=1+leaf(u),check(bas<<=leaf(u));
REP(u)if(dp[v]!=W){
dep[v]=dep[u]+1,pre[v]=u,dfs1(v),siz[u]+=siz[v];
if(cnt[u]=1ll*cnt[u]*cnt[v]%mod,siz[v]>siz[wes[u]])wes[u]=v;
}
REP(u)if(dp[v]==W)dfs1(v);
}
V upd(int p){t[p]=t[lc]+a[p]+t[rc];}
V add(int x,int w){
if(w)sum[x]=1ll*sum[x]*w%mod,a[x].c=1ll*a[x].c*w%mod;
else if(!zero[x]++)a[x].c=0;
}
V del(int x,int w){
if(w=Pow(w,mod-2))sum[x]=1ll*sum[x]*w%mod,a[x].c=1ll*a[x].c*w%mod;
else if(!--zero[x])a[x].c=sum[x];
}
V build(int&p,int L,int R){
if(L>R)return;
int sum=0,now=0,x;
FOR(i,L,R)sum+=siz[tmp[i]];
for(x=L,sum>>=1;(now+=siz[tmp[x]])<sum;x++);
p=tmp[x],build(lc,L,x-1),build(rc,x+1,R),fa[lc]=fa[rc]=p;
}
V init(int p){if(p)init(lc),init(rc),upd(p);}
V dfs2(int u,int p){
id[tmp[++tot]=u]=m,siz[u]-=siz[wes[u]],sum[u]=1,co[u]=p;
if(wes[u])a[u]={cnt[u],sum[u]=mod-1},dfs2(wes[u],p),top[u]=top[wes[u]];
else{
if(leaf(u)&&(a[u]={(u<=W)+(u<W),0},dep[u]&1))a[u].b=cnt[u]-a[u].b;
build(top[u],1,tot),tot=0;
}
REP(u)if(v!=wes[u]&&dp[v]!=W)dfs2(v,p),fa[top[v]]=u,init(top[v]),add(u,t[top[v]].b);
}
V build(int u){
dfs2(m=u,sgn[dep[u]&1]),init(top[u]),add(0,(cnt[u]+mod-t[top[u]].b)%mod);
REP(u)if(dp[v]==W)build(v);
}
V init(){dfs0(dep[1]=1),W=dp[1],dfs1(sum[0]=1),tot=0,build(m=1);}
V modify(int p){
int x=id[p];
del(0,cnt[x]+mod-t[top[x]].b);
for(a[p]={1,0};p;p=fa[p]){
if(p==top[p]&&fa[p])del(fa[p],t[p].b);
upd(p);
if(p==top[p]&&fa[p])add(fa[p],t[p].b);
}
add(0,cnt[x]+mod-t[top[x]].b);
}
V work(){
FOR(i,1,n){
check(ans[i]=bas+mod-a[0].c);
if(W+i<=n&&leaf(W+i)&&co[W+i]<0)modify(W+i);
if(W-i>=2&&leaf(W-i)&&co[W-i]>0)modify(W-i);
}
ans[0]=0,ans[n]=bas-1;
ROF(i,n,1)check(ans[i]+=mod-ans[i-1]);
FOR(i,L,R)cout<<ans[i]<<' ';
}
int main(){
input();
init();
work();
return 0;
}
```
起码 10 个月没写动态 dp 了,写了好久