luogu P6773 [NOI2020] 命運
阿新 • • 發佈:2022-03-02
題面傳送門
首先顯然有一個\(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); }