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

题面

CF

有一棵树,每条边有一个颜色(黑白)和一个权值,定义一条路径是好的,当且仅当这条路径上所有边的黑白颜色个数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(点分治)的更多相关文章

  1. 【CF833D】Red-Black Cobweb

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

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

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

  3. Codeforces 833D Red-Black Cobweb [点分治]

    洛谷 Codeforces 思路 看到树上路径的统计,容易想到点分治. 虽然只有一个限制,但这个限制比较麻烦,我们把它拆成两个. 设黑边有\(a\)条,白边有\(b\)条,那么有 \[ 2a\geq ...

  4. Codeforces 833D Red-black Cobweb【树分治】

    D. Red-black Cobweb time limit per test:6 seconds memory limit per test:256 megabytes input:standard ...

  5. CF833D Red-Black Cobweb

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

  6. 题解 CF833D Red-Black Cobweb

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

  7. 【CDQ分治】[HNOI2010]城市建设

    题目链接 线段树分治+LCT只有80 然后就有了CDQ分治的做法 把不可能在生成树里的扔到后面 把一定在生成树里的扔到并查集里存起来 分治到l=r,修改边权,跑个kruskal就行了 由于要支持撤销, ...

  8. URAL 1181 Cutting a Painted Polygon【递归+分治】

    题目: http://acm.timus.ru/problem.aspx?space=1&num=1181 http://acm.hust.edu.cn/vjudge/contest/view ...

  9. POJ 2114 点分治

    思路: 点分治 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> u ...

随机推荐

  1. Open Live Writer安装教程

    配置步骤: 1.在菜单中选择"工具">"帐户",出现下面的画面: 2.点击"添加按钮",在出现的窗口中选择"其他日志服务&q ...

  2. iOS--LaunchImage启动页设置及问题解决

    在Assets.xcassets中使用LaunchImage来设置启动图:   一.根据不同屏幕尺寸的需求设置不同的图片,可以参照下图: 1.点击Image.xcassets 进入图片管理,然后右击, ...

  3. XT535

    今天金山误删了一个文件,把手机系统整坏了,故刷了个机,刷机教程: http://bbs.dospy.com/thread-15027415-1-623-1.html 中间安装了个驱动精灵,否则手机开启 ...

  4. Python_阻塞IO、非阻塞IO、IO多路复用

    0.承上 进程: 计算机里最小的资源分配单位: 数据隔离, 利用多核,数据不安全. 线程: 计算机中最小的CPU调度单位: 数据共享,GIL锁,数据不安全. 协程: 线程的一部分,是有用户来调度的; ...

  5. Day 4-1 模块的导入方法和路径

    什么是模块? 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护. 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码 ...

  6. SQL Server 2014备份维护计划

    1.      数据库 -> [管理]-> [维护计划]  -> [新建维护计划](如果没有操作过可以,选择“维护计划向导”): 2.      直接点击下一步,然后填写计划名称.说 ...

  7. php5.6.x到php7.0.x特性

    php5.6.x到php7.0.x特性 1.标量类型声明 字符串(string), 整数 (int), 浮点数 (float), 布尔值 (bool),callable,array,self,Clas ...

  8. 移动端Web界面滚动touch事件

    解决办法一: elem.addEventListener( 'touchstart', fn, { passive: false } ); 解决办法二: * { touch-action: pan-y ...

  9. Java多线程4:Thread中的静态方法

    一.Thread类中的静态方法 Thread类中的静态方法是通过Thread.方法名来调用的,那么问题来了,这个Thread指的是哪个Thread,是所在位置对应的那个Thread嘛?通过下面的例子可 ...

  10. 【.NET】.NET MVC4 微信扫一扫功能实现-附全部代码

    写在前面的    首先在调用微信的JS-SDK接口的时候需要仔细阅读一下官方的注意事项,否则可能事倍功半.这里先大概概述一下主要的流程,首先,使用微信扫一扫需要一个已经通过认证的公众号:其次,需要知道 ...