luogu P6773 [NOI2020] 命运
题面传送门
首先显然有一个\(O(2^mm\log m)\)的容斥,但是和这道题好像一点关系没有。
所以这道题的关键就是不要去想容斥
发现如果现在深度从下往上确定到第\(i\)条边,那么我们只需要关注底下往上还没有一条边的限制的最近的即可。
因为如果最近的都满足了,那么剩下的一定也能满足。
然后就可以写出一个\(O(n^2)\)的dp了。设\(dp_{i,j}\)表示处理到\(i\)这个点,现在未处理限制的最小深度为\(j\)的方案数。
大概合并两个子树时对于每个\(dp_{u,j}\)都从深度小于它的\(dp_{v,k}\)转移。
然后这个显然可以线段树合并,就优化到\(O(n\log n)\)了。
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N (500000+5)
#define M (N*50)+5
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
#define Bmod(x,y) (x+y>=mod?x+y-mod:x+y)
using namespace std;
int n,m,x,y,Ro[N+5],d[N+5];vector<int> S[N],Q[N];const int Inv2=(mod+1)/2;
namespace Tree{
int cnt,L[M],R[M],F[M],G[M];I void Up(int now){F[now]=Bmod(F[L[now]],F[R[now]]);}I void PF(int x,ll w){x&&(F[x]=1ll*F[x]*w%mod,G[x]=1ll*G[x]*w%mod);}I void P(int now){G[now]^1&&(PF(L[now],G[now]),PF(R[now],G[now]),G[now]=1);}
I ll Qry(int x,int y,int &now,int l=0,int r=n){if(!now||x<=l&&r<=y) return F[now];int m=l+r>>1;P(now);ll Fs=0;x<=m&&(Fs+=Qry(x,y,L[now],l,m));y>m&&(Fs+=Qry(x,y,R[now],m+1,r));return Fs>mod?Fs-mod:Fs;}
I void Ins(int x,ll y,int &now,int l=0,int r=n){!now&&(G[now=++cnt]=1);F[now]=Bmod(y,F[now]);if(l==r) return;P(now);int m=l+r>>1;x<=m?Ins(x,y,L[now],l,m):Ins(x,y,R[now],m+1,r);}
I void Del(int x,int y,int &now,int l=0,int r=n){if(!now||x<=l&&r<=y) {now=0;return;}P(now);int m=l+r>>1;x<=m&&(Del(x,y,L[now],l,m),0);y>m&&(Del(x,y,R[now],m+1,r),0);Up(now);}
I int ME(int x,int y,ll F1=0,ll F2=0,int l=0,int r=n){
if(!x||!y) return x?PF(x,F2):PF(y,F1),x|y;int m=l+r>>1;if(l==r) return PF(x,F2+F[y]),PF(y,F1),F[x]=Bmod(F[y],F[x]),x;P(x);P(y);
R[x]=ME(R[x],R[y],Bmod(F1,F[L[x]]),Bmod(F2,F[L[y]]),m+1,r);L[x]=ME(L[x],L[y],F1,F2,l,m);return Up(x),x;
}
}
struct IO{
static const int S=1<<21;
char buf[S],*p1,*p2;int st[105],Top;
~IO(){clear();}
inline void clear(){fwrite(buf,1,Top,stdout);Top=0;}
inline void pc(const char c){Top==S&&(clear(),0);buf[Top++]=c;}
inline char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
inline IO&operator >> (char&x){while(x=gc(),x==' '||x=='\n'||x=='\r');return *this;}
template<typename T>inline IO&operator >> (T&x){
x=0;bool f=0;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') f^=1;ch=gc();}
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=gc();
f?x=-x:0;return *this;
}
inline IO&operator << (const char c){pc(c);return *this;}
template<typename T>inline IO&operator << (T x){
if(x<0) pc('-'),x=-x;
do{st[++st[0]]=x%10,x/=10;}while(x);
while(st[0]) pc('0'+st[st[0]--]);return *this;
}
}fin,fout;
I void dfs(int x,int La){d[x]=d[La]+1;Tree::Ins(0,1,Ro[x]);for(RI i:S[x]) i^La&&(dfs(i,x),Ro[x]=Tree::ME(Ro[x],Ro[i]),0);for(RI i:Q[x]) Tree::Ins(d[i],Tree::Qry(0,d[i]-1,Ro[x]),Ro[x]),Tree::Del(0,d[i]-1,Ro[x]);Tree::Del(d[x],n,Ro[x]);Tree::Ins(0,Tree::Qry(0,n,Ro[x]),Ro[x]);}
int main(){
freopen("1.in","r",stdin);
RI i;fin>>n;for(i=1;i<n;i++) fin>>x>>y,S[x].PB(y),S[y].PB(x);fin>>m;while(m--) fin>>x>>y,Q[y].PB(x);dfs(1,0);printf("%lld\n",Tree::Qry(0,0,Ro[1])*Inv2%mod);
}