「AHOI / HNOI2018」毒瘤 (DDP)(鏈分治)

LOJLOJ 傳送門

  • 題解:首先考慮一棵樹怎麼做,就是樹形 dpdp,然後我們可以枚舉每一條邊怎麼選,顯然有 3 種情況
    進一步發現只需要枚舉兩種,即強制 uuvv 不選,和強制 uu 不選 vv 隨意
    那麼現在的問題就是每次 banban 掉一些點選一些點不選,動態更新根節點的 dpdp
    然後把轉移寫成矩陣的形式鏈分治,由於可以除 00 所以手寫了一個用 x0yx*0^y 表示每個數的類
    複雜度 O(n+k2klog(n)2)O(n+k*2^k*log(n)^2) 被虛樹吊打
#include<bits/stdc++.h>
#define pb push_back
#define cs const
using namespace std;
int read(){
	int cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
	while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
	return cnt * f;
}
cs int N = 1e5 + 50, K = 15;
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int ksm(int a, int b){ int ans=1; for(;b;b>>=1,a=mul(a,a)) if(b&1) ans=mul(ans,a); return ans; }
void Add(int &a, int b){ a = add(a, b); }
void Mul(int &a, int b){ a = mul(a, b); }
int n, m, k, u[K], v[K];
vector<int> G[N];
int sz[N], son[N], fa[N], dep[N], in[N], top[N], bot[N], sgn;
struct mat{
	int a[2][2];
	mat(int _x=0, int _y=0){ a[0][0]=a[1][0]=_x; a[0][1]=_y; a[1][1]=0; }
	mat operator * (cs mat &A){
		mat B; 
		for(int i=0; i<2; i++) for(int k=0; k<2; k++) if(a[i][k])
		for(int j=0; j<2; j++) if(A.a[k][j]) Add(B.a[i][j],mul(a[i][k],A.a[k][j]));
		return B;
	}
	int vl(){ return add(a[0][0],a[0][1]); }
};
struct num{
	int x,y;
	num(){ x = y = 1; }
	void operator = (int v){ v ? (x=v,y=0) : (x=y=1); }
	void operator *= (int v){ v ? x=mul(x,v) : ++y; }
	void operator /= (int v){ v ? x=mul(x,ksm(v,Mod-2)) : --y; }
	operator int()cs{ return y?0:x; }
};
void pre_dfs(int u, int f){
	sz[u] = 1;
	for(int v : G[u]) if(v ^ f){
		fa[v] = u; dep[v] = dep[u]+1; pre_dfs(v,u);
		sz[u] += sz[v]; if(sz[son[u]]<sz[v]) son[u]=v;
	}
}
namespace SGT{
	cs int N = ::N<<2;
	mat vl[N];
	#define mid ((l+r)>>1)
	void pushup(int x){ vl[x] = vl[x<<1|1] * vl[x<<1]; }
	void modify(int x, int l, int r, int p, mat v){
		if(l == r){ vl[x] = v; return; }
		(p<=mid)?modify(x<<1,l,mid,p,v):modify(x<<1|1,mid+1,r,p,v); pushup(x);
	}
	mat query(int x, int l, int r, int L, int R){
		if(L<=l&&r<=R) return vl[x]; 
		if(R<=mid) return query(x<<1,l,mid,L,R);
		else if(L>mid) return query(x<<1|1,mid+1,r,L,R);
		else return query(x<<1|1,mid+1,r,L,R)*query(x<<1,l,mid,L,R);
	}
}
int f[N][2]; num coe[N][2];
void dfs(int u, int tp){
	top[u] = tp; in[u]=++sgn;
	if(son[u]) dfs(son[u],tp), bot[u]=bot[son[u]];
	else bot[u]=u; 
	coe[u][0]=1; coe[u][1]=1;
	for(int v : G[u]) if(v!=fa[u]&&v!=son[u])
		dfs(v,v), coe[u][0]*=add(f[v][0],f[v][1]), coe[u][1]*=f[v][0];
	SGT::modify(1,1,n,in[u],mat(coe[u][0],coe[u][1]));
	if(son[u]) f[u][0]=mul(coe[u][0],add(f[son[u]][0],f[son[u]][1])), f[u][1]=mul(coe[u][1],f[son[u]][0]);
	else f[u][0]=f[u][1]=1;
}
int state[N];
void upt(int u){
	mat now;
	while(u){
		int tp = fa[top[u]];
		if(tp){
			now = SGT::query(1,1,n,in[top[u]],in[bot[u]]);
			coe[tp][0]/=now.vl(), coe[tp][1]/=now.a[0][0];
		}
		if(state[u]==1) SGT::modify(1,1,n,in[u],mat(coe[u][0],0));
		else if(state[u]==2) SGT::modify(1,1,n,in[u],mat(0,coe[u][1]));
		else SGT::modify(1,1,n,in[u],mat(coe[u][0],coe[u][1]));
		if(tp){
			now = SGT::query(1,1,n,in[top[u]],in[bot[u]]);
			coe[tp][0]*=now.vl(), coe[tp][1]*=now.a[0][0];
		} u = tp;
	}
}
int anc[N]; 
int find(int x){ return x==anc[x]?x:anc[x]=find(anc[x]); }
bool ck(int S){
	for(int i=0; i<k; i++) state[u[i]]=state[v[i]]=0;
	for(int i=0; i<k; i++){
		if(S>>i&1){
			if(state[u[i]]==1) return false; state[u[i]]=2;
			if(state[v[i]]==2) return false; state[v[i]]=1;
		}
		else{
			if(state[u[i]]==2) return false; state[u[i]]=1;
		}
	} return true;
}
int main(){
	n = read(), m = read();
	for(int i=1; i<=n; i++) anc[i]=i;
	for(int i=1,x,y; i<=m; i++){
		x=read(), y=read();
		if(find(x)^find(y)) G[x].pb(y),G[y].pb(x),anc[find(x)]=find(y);
		else u[k]=x,v[k++]=y;
	}
	pre_dfs(1,0); dfs(1,1); int as = 0;
	for(int S=0; S<(1<<k); S++){
		if(!ck(S)) continue;
		for(int i=0; i<k; i++){
			if(S>>i&1) upt(u[i]), upt(v[i]);
			else upt(u[i]);
		}
		Add(as,SGT::query(1,1,n,in[1],in[bot[1]]).vl());
		for(int i=0; i<k; i++) state[u[i]]=state[v[i]]=0;
		for(int i=k-1; ~i; i--){
			if(S>>i&1) upt(v[i]), upt(u[i]); 
			else upt(u[i]); 
		}
	} cout << as; return 0;
}
發佈了651 篇原創文章 · 獲贊 98 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章