题目传送门

题目大意

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

\(n\le 10^5\),答案对 \(10^9+7\) 取模。

思路

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

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

时间复杂度 \(\Theta(n\log^2 n)\) 。

\(\texttt{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 ('\n');
return 0;
}

题解 CF833D Red-Black Cobweb的更多相关文章

  1. 【CF833D】Red-Black Cobweb(点分治)

    [CF833D]Red-Black Cobweb(点分治) 题面 CF 有一棵树,每条边有一个颜色(黑白)和一个权值,定义一条路径是好的,当且仅当这条路径上所有边的黑白颜色个数a,b满足2min(a, ...

  2. 【CF833D】Red-Black Cobweb

    [CF833D]Red-Black Cobweb 题面 洛谷 题解 看到这种统计路径的题目当然是淀粉质啦. 考虑转化一下信息设一条路径上有红点\(a\)个,黑点\(b\)个 则\(2min(a,b)\ ...

  3. Hdoj 1312.Red and Black 题解

    Problem Description There is a rectangular room, covered with square tiles. Each tile is colored eit ...

  4. CF833D Red-Black Cobweb

    题面 题解 点分治大火题... 设白边数量为$a$,黑边为$b$,则$2min(a,b)\geq max(a,b)$ 即$2a\geq b\;\&\&2b\geq a$ 考虑点分治时如 ...

  5. 题解报告:hdu 1312 Red and Black(简单dfs)

    Problem Description There is a rectangular room, covered with square tiles. Each tile is colored eit ...

  6. poj 1979 Red and Black 题解《挑战程序设计竞赛》

    地址 http://poj.org/problem?id=1979 Description There is a rectangular room, covered with square tiles ...

  7. 【CF1425B】 Blue and Red of Our Faculty! 题解

    原题链接 简要翻译: 有一个连通图,A和B同时从点1出发,沿不同的路径前进.原本,图上的每一条边都是灰色的.A将经过的边涂成红色,B将经过的边涂成蓝色的.每个回合每个人只能走灰色的边.当某个回合中不存 ...

  8. CF833D Red-Black Cobweb 点分治、树状数组

    传送门 统计所有路径的边权乘积的乘积,不难想到点分治求解. 边权颜色比例在\([\frac{1}{2},2]\)之间,等价于\(2B \geq R , 2R \geq B\)(\(R,B\)表示红色和 ...

  9. 洛谷 CF399B【Red and Blue Balls】题解

    n年没有更博客:我总结出了规律,当学的东西很难得时候都去学习,没有时间写博客,只有 内容对于我这种蒟蒻友好,又让我非常闲的慌时才写博客,这种博客以后也没有价值(也有些是做完一道题有成就感写的) 最近内 ...

随机推荐

  1. Python和java的选择

    它是什么? Java是一种通用的面向对象的编程语言,主要用于开发从移动应用程序到Web到企业应用程序的各种应用程序. Python是一种高级的面向对象的编程语言,主要用于Web开发,人工智能,机器学习 ...

  2. spring-data-redis 动态切换数据源

    最近遇到了一个麻烦的需求,我们需要一个微服务应用同时访问两个不同的 Redis 集群.一般我们不会这么使用 Redis,但是这两个 Redis 本来是不同业务集群,现在需要一个微服务同时访问. 其实我 ...

  3. 微信小程序切换选中状态

     实现的主要思路是根据每一项的index值,动态改变idx值,当index==idx值的时候,添加点击选中样式的类名. wxml: <scroll-view scroll-x="tru ...

  4. 云原生 AI 前沿:Kubeflow Training Operator 统一云上 AI 训练

    分布式训练与 Kubeflow 当开发者想要讲深度学习的分布式训练搬上 Kubernetes 集群时,首先想到的往往就是 Kubeflow 社区中形形色色的 operators,如 tf-operat ...

  5. [考试总结]noip模拟39

    不写那么多没用的了 开题就发现 \(T4\) 原题, \(T1\) 大水题. 然后发现 \(T4\) 忘了.... 不扯了 打地鼠 大水题,我代码都不想放... 算了,还是放一下吧.. #includ ...

  6. Redis的读写分离

    1.概述 随着企业业务的不断扩大,请求的并发量不断增长,Redis可能终会出现无法负载的情况,此时我们就需要想办法去提升Redis的负载能力. 读写分离(主从复制)是一个比较简单的扩展方案,使用多台机 ...

  7. linux下制作img文件

    一.简介 制作img文件可以使用linux系统中的dd命令制作,Linux dd 命令用于读取.转换并输出数据.dd 可从标准输入或文件中读取数据,根据指定的格式来转换数据,再输出到文件.设备或标准输 ...

  8. 聊聊ReentrantLock基于AQS的公平锁和非公平锁的实现区别

    ReentrantLock锁的实现是基于AQS实现的,所以先简单说下AQS: AQS是AbstractQueuedSynchronizer缩写,顾名思义:抽象的队列同步器,它是JUC里面许多同步工具类 ...

  9. 在C++11编译环境中,简单自测了一下C++标准库中的string/vector和迭代器,记录一下

    #include <iostream> #include <vector> using namespace std; int main() { //////////////// ...

  10. git撤销文件的修改

    git撤销某个文件的修改,分为两种情况:1.在工作区修改,但并未提交到暂存区(即并没有add).对于单个文件的撤销修改而言,使用下面方法. git checkout -- 文件名 若想撤销工作区中所有 ...