【CF833D】Red-Black Cobweb(点分治)
【CF833D】Red-Black Cobweb(点分治)
题面
有一棵树,每条边有一个颜色(黑白)和一个权值,定义一条路径是好的,当且仅当这条路径上所有边的黑白颜色个数a,b满足2min(a,b)>=max(a,b),一条路径的权值为路径上所有边的权值的乘积,求所有好的路径的权值乘积.
\(n<=10^5\)
题解
首先看到求所有路径相关的内容,不难想到点分治。
两个限制可以转化为需要同时满足:\(2a\ge b,2b\ge a\)。
对于两条路径\(a1,b1/a2,b2\)考虑如何合并。
需要满足的两个条件就变成了\(2(a1+a2)\ge b1+b2\)以及\(2(b1+b2)\ge a1+a2\)
再稍微拆开看看就变成了\(2a1-b1\ge b2-2a2\),另一个类似。
这里怎么计算总的方案数,那么就用总数减去不合法的,如果不合法显然只会有一个不等式不合法(因为另外一个不等式是由最大值的两倍大于较小值得到的,它无论如何都会是对的),那么只需要统计有一个不合法的所有链就好了。
#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 100100
#define MOD 1000000007
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int fpow(int a,int b){int s=1;while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}return s;}
struct Line{int v,next,w,c;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v,int w,int c){e[cnt]=(Line){v,h[u],w,c};h[u]=cnt++;}
int Size,mx,rt,size[MAX];bool vis[MAX];
int n,N,ans,ans1=1,ans2=1;
int lb(int x){return x&(-x);}
struct BIT
{
int c1[MAX<<3],c2[MAX<<3];
void pre(){for(int i=1;i<=N;++i)c1[i]=1,c2[i]=0;}
void Modify(int x,int w){while(x<=N)c1[x]=1ll*c1[x]*w%MOD,c2[x]+=1,x+=lb(x);}
void Clear(int x){while(x<=N)c1[x]=1,c2[x]=0,x+=lb(x);}
int Querys(int x){int s=1;while(x)s=1ll*s*c1[x]%MOD,x-=lb(x);return s;}
int Queryt(int x){int s=0;while(x)s+=c2[x],x-=lb(x);return s;}
int Querys(int l,int r){return 1ll*Querys(r)*fpow(Querys(l-1),MOD-2)%MOD;}
int Queryt(int l,int r){return Queryt(r)-Queryt(l-1);}
}c1,c2;
void Getroot(int u,int ff)
{
int ret=0;size[u]=1;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(v==ff||vis[v])continue;
Getroot(v,u);size[u]+=size[v];ret=max(ret,size[v]);
}
ret=max(ret,Size-size[u]);
if(ret<mx)mx=ret,rt=u;
}
struct Pair{int a,b,w;}S[MAX],T[MAX];
int top,sum,W,SW,py;
void dfs(int u,int ff,int a,int b,int w)
{
T[++top]=(Pair){a,b,w};W=1ll*w*W%MOD;
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff&&!vis[e[i].v])
dfs(e[i].v,u,a+(e[i].c^1),b+e[i].c,1ll*w*e[i].w%MOD);
}
void Divide(int u)
{
vis[u]=true;sum=0;SW=1;S[++sum]=(Pair){0,0,1};
c1.Modify(py,1);c2.Modify(py,1);
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(vis[v])continue;
top=0;W=1;dfs(e[i].v,u,e[i].c^1,e[i].c,e[i].w);
ans1=1ll*ans1*fpow(W,sum)%MOD*fpow(SW,top)%MOD;
SW=1ll*SW*W%MOD;
for(int j=1;j<=top;++j)
{
int A=T[j].b-2*T[j].a-1+py,B=T[j].a-2*T[j].b-1+py;
ans2=1ll*ans2*c1.Querys(2,A)%MOD*fpow(T[j].w,c1.Queryt(2,A))%MOD;
ans2=1ll*ans2*c2.Querys(2,B)%MOD*fpow(T[j].w,c2.Queryt(2,B))%MOD;
}
for(int j=1;j<=top;++j)
{
int A=2*T[j].a-T[j].b+py;c1.Modify(A,T[j].w);
int B=2*T[j].b-T[j].a+py;c2.Modify(B,T[j].w);
S[++sum]=T[j];
}
}
for(int j=1;j<=sum;++j)
{
int A=2*S[j].a-S[j].b+py;c1.Clear(A);
int B=2*S[j].b-S[j].a+py;c2.Clear(B);
}
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(vis[v])continue;
Size=mx=size[v];Getroot(v,u);
Divide(rt);
}
}
int main()
{
n=read();py=n+n+2;N=5*n;c1.pre();c2.pre();
for(int i=1,u,v,w,c;i<n;++i)
u=read(),v=read(),w=read(),c=read(),Add(u,v,w,c),Add(v,u,w,c);
Size=mx=n;Getroot(1,0);Divide(rt);
ans=1ll*ans1*fpow(ans2,MOD-2)%MOD;
printf("%d\n",ans);
return 0;
}
【CF833D】Red-Black Cobweb(点分治)的更多相关文章
- 【CF833D】Red-Black Cobweb
[CF833D]Red-Black Cobweb 题面 洛谷 题解 看到这种统计路径的题目当然是淀粉质啦. 考虑转化一下信息设一条路径上有红点\(a\)个,黑点\(b\)个 则\(2min(a,b)\ ...
- CF833D Red-Black Cobweb 点分治、树状数组
传送门 统计所有路径的边权乘积的乘积,不难想到点分治求解. 边权颜色比例在\([\frac{1}{2},2]\)之间,等价于\(2B \geq R , 2R \geq B\)(\(R,B\)表示红色和 ...
- Codeforces 833D Red-Black Cobweb [点分治]
洛谷 Codeforces 思路 看到树上路径的统计,容易想到点分治. 虽然只有一个限制,但这个限制比较麻烦,我们把它拆成两个. 设黑边有\(a\)条,白边有\(b\)条,那么有 \[ 2a\geq ...
- Codeforces 833D Red-black Cobweb【树分治】
D. Red-black Cobweb time limit per test:6 seconds memory limit per test:256 megabytes input:standard ...
- CF833D Red-Black Cobweb
题面 题解 点分治大火题... 设白边数量为$a$,黑边为$b$,则$2min(a,b)\geq max(a,b)$ 即$2a\geq b\;\&\&2b\geq a$ 考虑点分治时如 ...
- 题解 CF833D Red-Black Cobweb
题目传送门 题目大意 给出一个 \(n\) 个点的树,每条边有边权和颜色 \(0,1\) ,定义一条链合法当且仅当 \(0,1\) 颜色的边数之比小于等于 \(2\) ,求所有合法的链的边权之积的积. ...
- 【CDQ分治】[HNOI2010]城市建设
题目链接 线段树分治+LCT只有80 然后就有了CDQ分治的做法 把不可能在生成树里的扔到后面 把一定在生成树里的扔到并查集里存起来 分治到l=r,修改边权,跑个kruskal就行了 由于要支持撤销, ...
- URAL 1181 Cutting a Painted Polygon【递归+分治】
题目: http://acm.timus.ru/problem.aspx?space=1&num=1181 http://acm.hust.edu.cn/vjudge/contest/view ...
- POJ 2114 点分治
思路: 点分治 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> u ...
随机推荐
- redis的spring的xml配置
<!-- 集群版配置 --> <bean id="jedisCluster" class="redis.clients.jedis.JedisClust ...
- Azure系列2.1.4 —— BlobInputStream
(小弟自学Azure,文中有不正确之处,请路过各位大神指正.) 网上azure的资料较少,尤其是API,全是英文的,中文资料更是少之又少.这次由于公司项目需要使用Azure,所以对Azure的一些学习 ...
- JS中的<a>标签
<a>标签可定义锚.一个锚有两种用法: 通过使用 href 属性,创建一个到另外一个文档的链接 通过使用 name 或 id 属性,创建一个文档内部的书签 如果是在 HTML 5 中,它定 ...
- C# Note25: .Net Core
.NET Core全面扫盲贴 .NET Core与.NET Framework.Mono之间的关系 https://www.postgresql.org/
- 剑指offer(16)栈的压入、弹出序列
题目: 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈 ...
- 剑指offer(7)
今天的几道题目都是关于斐波那契数列的. 题目1: 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0). n<=39 传统的方法采用递归函数,这种 ...
- Flutter上拉加载下拉刷新---flutter_easyrefresh
前言 Flutter默认不支持上拉加载,下拉刷新也仅仅支持Material的一种样式.Android开发使用过SmartRefreshLayout的小伙伴都知道这是一个强大的刷新UI库,集成了很多出色 ...
- 使用Elasticsearch 出现的拒绝连接
pom 文件 spring: elasticsearch: jest: uris: http://192.168.124.142:9201 # data: # elasticsearch: # clu ...
- mybatis逆向工程,实现join多表查询,避免多表相同字段名的陷阱
mybatis逆向工程,实现join多表查询,避免多表相同字段名的陷阱 前言:使用 mybatis generator 生成表格对应的pojo.dao.mapper,以及对应的example的 ...
- SQL Server 数据库try catch 存储过程
SQL Server 在生产环境中这样写存储过程的坑都避免了吗? 原文链接: http://www.cnblogs.com/chenmh/p/7856777.html 概述 最近因为业务的需求写了一段 ...