【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. SQL性能优化-order by语句的优化

    原文:http://bbs.landingbj.com/t-0-243203-1.html 在某些情况中,MySQL可以使用一个索引来满足ORDER BY子句,而不需要额外的排序.where条件和or ...

  2. AngularJS路由使用案例

    AngularJS路由使用案例: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"& ...

  3. checkout 多选 全选(亲测有效)

    <input type="button" id="btn1" value="全选"> <input type=" ...

  4. Linux上的一些基本常用命令

    上传下载文件:// 首先安装lrzsz # yum -y install lrzsz // 上传文件,执行命令rz,会跳出文件选择窗口,选择好文件,点击确认即可.# rz // 下载文件,执行命令sz ...

  5. K3 WISE安全认证方式

    k/3中间层注册三种安全认证方式: 交互式用户方式,网络服务方式,信任方式,是指组件服务中生成的COM+应用程序中的组件包的运行账户(注册中间层后产生很多ebo开头的和kdsvrmgr组件包). 三种 ...

  6. Vue 获得所选中目标的状态(checked)以及对应目标的数据,并进行相应的操作

    一.我们现在要拿取购物车中选中商品的状态和该商品的所有数据或者id <ul v-if="shopList.list.length>0"> <li class ...

  7. zepto的extend

    类型判断 var class2type = {},toString = class2type.toString,$={}; //判断类型 function type(obj) { return obj ...

  8. mapreduce join

    MapReduce Join 对两份数据data1和data2进行关键词连接是一个很通用的问题,如果数据量比较小,可以在内存中完成连接. 如果数据量比较大,在内存进行连接操会发生OOM.mapredu ...

  9. Python:matplotlib绘制直方图

    使用hist方法来绘制直方图:     绘制直方图,最主要的是一个数据集data和需要划分的区间数量bins,另外你也可以设置一些颜色.类型参数: plt.hist(np.random.randn(1 ...

  10. 老男孩python学习自修第四天【字典的使用】

    dict = {key1:value1, key2:value2} 定义字典 dict[key] = value 设置字典中指定健的值 dict.pop(key) 删除字典中指定健 dict.popi ...