1. 程式人生 > 其它 >luogu P6773 [NOI2020] 命運

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);
}