• 题解 CF833D Red-Black Cobweb


    题目传送门

    题目大意

    给出一个 (n) 个点的树,每条边有边权和颜色 (0,1) ,定义一条链合法当且仅当 (0,1) 颜色的边数之比小于等于 (2) ,求所有合法的链的边权之积的积。

    (nle 10^5),答案对 (10^9+7) 取模。

    思路

    边分治板题,但是因为边界问题爆炸了。。。

    首先先容斥一下,即总答案除以不合法答案,然后你发现总答案特别好求,不合法方案可是使用边分治解决。

    时间复杂度 (Theta(nlog^2 n))

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define mod 1000000007
    #define MAXN 800005
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    int n,ans = 1;
    
    int qkpow (int a,int b){
    	int res = 1;for (;b;b >>= 1,a = 1ll * a * a % mod) if (b & 1) res = 1ll * res * a % mod;
    	return res;
    }
    int inv (int x){return qkpow (x,mod - 2);}
    
    namespace Graph{
    #define PII pair<int,int>
    	int cnt = 1,toop = 1,pres[MAXN],to[MAXN << 1],wei[MAXN << 1],col[MAXN << 1],nxt[MAXN << 1],head[MAXN],siz[MAXN];bool vis[MAXN];
    	void Add_Edge (int u,int v,int w,int c){
    		to[++ toop] = v,wei[toop] = w,col[toop] = c,nxt[toop] = head[u],head[u] = toop;
    		to[++ toop] = u,wei[toop] = w,col[toop] = c,nxt[toop] = head[v],head[v] = toop;
    	}
    	struct node{
    		int R,B,dis;
    	};
    	node *f,T1[MAXN],T2[MAXN];
    	void dfs (int u,int fa,int totr,int totb,int pre){
    		if (u <= n) f[++ cnt] = node {totr,totb,pre};
    		for (Int i = head[u];i;i = nxt[i]){
    			int v = to[i];
    			if (v == fa || vis[i]) continue;
    			dfs (v,u,totr + (col[i] == 0),totb + (col[i] == 1),1ll * pre * wei[i] % mod);
    		}
    	}
    	int ed,lim,Siz,lena,lenb;
    	void findedge (int u,int fa){//找重边
    		siz[u] = 1;
    		for (Int i = head[u];i;i = nxt[i]){
    			int v = to[i];
    			if (v == fa || vis[i]) continue;
    			findedge (v,u),siz[u] += siz[v];
    			int tmp = max (siz[v],Siz - siz[v]);
    			if (tmp < lim) ed = i,lim = tmp;
    		} 
    	}
    	bool cmp1 (node a,node b){return 2 * a.B - a.R < 2 * b.B - b.R;}
    	bool cmp2 (node a,node b){return 2 * a.R - a.B < 2 * b.R - b.B;}
    	void Solve (int u,int S){
    		if (S <= 1) return ;
    		lim = Siz = S,findedge (u,0),vis[ed] = vis[ed ^ 1] = 1;
    		cnt = 0,f = T1,dfs (to[ed],0,0,0,1),lena = cnt;
    		cnt = 0,f = T2,dfs (to[ed ^ 1],0,0,0,1),lenb = cnt;
    		for (Int i = 1;i <= lenb;++ i) T2[i].R += (col[ed] == 0),T2[i].B += (col[ed] == 1),T2[i].dis = 1ll * T2[i].dis * wei[ed] % mod;
    		sort (T1 + 1,T1 + lena + 1,cmp1);
    		pres[0] = 1;for (Int i = 1;i <= lena;++ i) pres[i] = 1ll * pres[i - 1] * T1[i].dis % mod;
    		for (Int i = 1;i <= lenb;++ i){
    			int now = T2[i].R - 2 * T2[i].B,l = 1,r = lena,fuckans = 0;
    			while (l <= r){
    				int mid = (l + r) >> 1;
    				if (2 * T1[mid].B - T1[mid].R < now) fuckans = mid,l = mid + 1;
    				else r = mid - 1;
    			}
    			ans = 1ll * ans * qkpow (T2[i].dis,fuckans) % mod * pres[fuckans] % mod;
    		}
    		sort (T1 + 1,T1 + lena + 1,cmp2);
    		pres[0] = 1;for (Int i = 1;i <= lena;++ i) pres[i] = 1ll * pres[i - 1] * T1[i].dis % mod;
    		for (Int i = 1;i <= lenb;++ i){
    			int now = T2[i].B - 2 * T2[i].R,l = 1,r = lena,fuckans = 0;
    			while (l <= r){
    				int mid = (l + r) >> 1;
    				if (2 * T1[mid].R - T1[mid].B < now) fuckans = mid,l = mid + 1;
    				else r = mid - 1;
    			}
    			ans = 1ll * ans * qkpow (T2[i].dis,fuckans) % mod * pres[fuckans] % mod;
    		}
    		int tx = to[ed],ty = to[ed ^ 1];
    		if (siz[tx] > siz[ty]) siz[tx] = S - siz[ty];
    		else siz[ty] = S - siz[tx];
    		Solve (tx,siz[tx]),Solve (ty,siz[ty]); 
    	} 
    }
    
    int cnt,all = 1,toop = 1,to[MAXN << 1],wei[MAXN << 1],col[MAXN << 1],nxt[MAXN << 1],head[MAXN],las[MAXN],siz[MAXN];
    
    void Add_Edge (int u,int v,int w,int c){
    	to[++ toop] = v,wei[toop] = w,col[toop] = c,nxt[toop] = head[u],head[u] = toop;
    	to[++ toop] = u,wei[toop] = w,col[toop] = c,nxt[toop] = head[v],head[v] = toop;
    }
    
    void dfs (int u,int fa){
    	siz[u] = 1;
    	for (Int i = head[u];i;i = nxt[i]){
    		int v = to[i],w = wei[i],c = col[i];
    		if (v == fa) continue;
    		if (!las[u]) las[u] = u,Graph::Add_Edge (u,v,w,c);
    		else ++ cnt,Graph::Add_Edge (las[u],cnt,1,-1),Graph::Add_Edge (las[u] = cnt,v,w,c);
    		dfs (v,u),siz[u] += siz[v],all = 1ll * all * qkpow (w,1ll * siz[v] * (n - siz[v]) % (mod - 1)) % mod;
    	}
    }
    
    signed main(){
    	read (n),cnt = n;
    	for (Int i = 2,u,v,w,c;i <= n;++ i) read (u,v,w,c),Add_Edge (u,v,w,c);
    	dfs (1,0),Graph::Solve (1,cnt),write (1ll * all * inv (ans) % mod),putchar ('
    ');
    	return 0;
    }
    
  • 相关阅读:
    Log4j的配置
    Linux笔记
    面对一个个路口
    切图布局知识点(四)——不定宽有背景文字块居中
    切图布局知识点(三)——左右布局
    切图布局知识点(二)——高度100%
    切图布局知识点(一)
    window下静默执行python脚本
    mysql 允许远程连接
    linux 防火墙
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13532077.html
Copyright © 2020-2023  润新知