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

传送门



统计所有路径的边权乘积的乘积,不难想到点分治求解。

边权颜色比例在\([\frac{1}{2},2]\)之间,等价于\(2B \geq R , 2R \geq B\)(\(R,B\)表示红色和黑色的边的条数)

所以我们可以在统计的时候,先把所有可能的路径全部乘进答案,然后除掉满足\(2B < R\)或者\(2R < B\)的路径的乘积。显然对于一条路径,这两个条件至多满足一个。

对于两条路径,它们红色、黑色的边数分别为\(B_1,R_1\)和\(B_2,R_2\),那么需要统计的就是\(R_1 - 2B_1 > 2B_2 - R_2\)或者\(B_1 - 2R_1 > 2R_2 - B_2\)的路径的信息。可以使用树状数组维护。

#include<iostream>
#include<cstdio>
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    char c = getchar();
    while(!isdigit(c))
        c = getchar();
    while(isdigit(c)){
        a = a * 10 + c - 48;
        c = getchar();
    }
    return a;
}

#define PII pair < int , int >
#define st first
#define nd second
const int MAXN = 1e5 + 7 , MOD = 1e9 + 7;

inline int poww(long long a , int b){
    int times = 1;
    while(b){
        if(b & 1) times = times * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return times;
}

struct Edge{int end , upEd , w , col;}Ed[MAXN << 1];
int head[MAXN] , N , nowSz , minSz , minInd , sum , ans , cnt , cntEd;
bool vis[MAXN];

struct BIT{
#define lowbit(x) ((x) & -(x))
    int BIT0[MAXN << 2] , BIT1[MAXN << 2];
    BIT(){fill(BIT0 , BIT0 + (MAXN << 2) , 1);}
    void add(int pos , int w , int tp){
        pos += 2 * N + 1;
        if(tp == -1) w = poww(w , MOD - 2);
        while(pos <= (N + 1) << 2){
            BIT0[pos] = 1ll * BIT0[pos] * w % MOD;
            BIT1[pos] += tp;
            pos += lowbit(pos);
        }
    }
    PII get(int pos){
        pos += 2 * N + 1;
        int tms = 1 , sum = 0;
        while(pos){
            tms = 1ll * tms * BIT0[pos] % MOD;
            sum += BIT1[pos];
            pos -= lowbit(pos);
        }
        return PII(tms , sum);
    }
}BIT1 , BIT2;

inline void addEd(int a , int b , int c , int d){
    Ed[++cntEd] = (Edge){b , head[a] , c , d};
    head[a] = cntEd;
}

void getSz(int x){
    vis[x] = 1; ++nowSz;
    for(int i = head[x] ; i ; i = Ed[i].upEd)
        if(!vis[Ed[i].end]) getSz(Ed[i].end);
    vis[x] = 0;
}

int getRt(int x){
    vis[x] = 1;
    int sz = 1 , maxSz = 0;
    for(int i = head[x] ; i ; i = Ed[i].upEd)
        if(!vis[Ed[i].end]){
            int t = getRt(Ed[i].end);
            sz += t; maxSz = max(maxSz , t);
        }
    maxSz = max(maxSz , nowSz - sz);
    if(minSz > maxSz){
        minSz = maxSz;
        minInd = x;
    }
    vis[x] = 0;
    return sz;
}

void addNd(int x , int w , int colR , int colB , int tp){
    sum = 1ll * sum * w % MOD; ++cnt;
    BIT1.add(2 * colR - colB , w , tp);
    BIT2.add(2 * colB - colR , w , tp);
    vis[x] = 1;
    for(int i = head[x] ; i ; i = Ed[i].upEd)
        if(!vis[Ed[i].end])
            addNd(Ed[i].end , 1ll * w * Ed[i].w % MOD , colR + Ed[i].col , colB + !Ed[i].col , tp);
    vis[x] = 0;
}

void qryNd(int x , int w , int colR , int colB){
    if(2 * colB >= colR && 2 * colR >= colB)
        ans = 1ll * ans * w % MOD;
    ans = 1ll * ans * sum % MOD * poww(w , cnt) % MOD;
    PII p = BIT1.get(colB - 2 * colR - 1) , q = BIT2.get(colR - 2 * colB - 1);
    ans = 1ll * ans * poww(1ll * p.st * q.st % MOD * poww(w , p.nd + q.nd) % MOD , MOD - 2) % MOD;
    vis[x] = 1;
    for(int i = head[x] ; i ; i = Ed[i].upEd)
        if(!vis[Ed[i].end])
            qryNd(Ed[i].end , 1ll * w * Ed[i].w % MOD , colR + Ed[i].col , colB + !Ed[i].col);
    vis[x] = 0;
}

void solve(int x){
    nowSz = cnt = 0; sum = 1; minSz = 1e9;
    getSz(x); getRt(x); x = minInd;
    vis[x] = 1;
    for(int i = head[x] ; i ; i = Ed[i].upEd)
        if(!vis[Ed[i].end]){
            qryNd(Ed[i].end , Ed[i].w , Ed[i].col , !Ed[i].col);
            addNd(Ed[i].end , Ed[i].w , Ed[i].col , !Ed[i].col , 1);
        }
    for(int i = head[x] ; i ; i = Ed[i].upEd)
        if(!vis[Ed[i].end])
            addNd(Ed[i].end , Ed[i].w , Ed[i].col , !Ed[i].col , -1);
    for(int i = head[x] ; i ; i = Ed[i].upEd)
        if(!vis[Ed[i].end])
            solve(Ed[i].end);
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
    //freopen("out","w",stdout);
#endif
    N = read();
    for(int i = 1 ; i < N ; ++i){
        int a = read() , b = read() , w = read() , col = read();
        addEd(a , b , w , col); addEd(b , a , w , col);
    }
    ans = 1;
    solve(1);
    cout << ans;
    return 0;
}

原文地址:https://www.cnblogs.com/Itst/p/10549404.html

时间: 2024-10-28 16:30:08

CF833D Red-Black Cobweb 点分治、树状数组的相关文章

HDU 5618:Jam&#39;s problem again(CDQ分治+树状数组处理三维偏序)

http://acm.hdu.edu.cn/showproblem.php?pid=5618 题意:-- 思路:和NEUOJ那题一样的.重新写了遍理解了一下,算作处理三维偏序的模板了. 1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 using namespace std; 6 #define INF 0x3f3f3f3f 7 #d

BZOJ 2683 简单题 cdq分治+树状数组

题意:链接 **方法:**cdq分治+树状数组 解析: 首先对于这道题,看了范围之后,二维的数据结构是显然不能过的,于是我们可能会考虑把一维排序之后另一位上数据结构什么的,然而cdq分治却能够很好的体现它的作用. 首先,对于每一个询问求和,显然是x在它左边的并且出现时间在它之前的所有的change对他可能会有影响. 我们按照x第一关键字,y第二关键字,操作第三关键字来排序所有的询问,然后在cdq的时候,每次递归处理左半区间,按照x动态的将y这一列的值加到树状数组里,来更新右半边的所有询问,注意这

XJOI NOIP2015模拟赛Day1 T2 ctps bitset优化 或 排序+cdq分治+树状数组+平衡树

题意: 4维空间中有1个点集A,|A|=n,用(a,b,c,d)表示每个点. 共有m个询问,每次询问输入一个点(a,b,c,d),求最大的S,其中S={p|p∈A且ap<=a,bp<=b,cp<=c,dp<=d},输出|S| 输入格式: 第一行n 接下来n行有n个4维点对 第n+2行有一个数m 再接下来m行每行有一个四维点对,表示每个询问 输出格式: 对于每个询问输出一个数 **方法:**bitset优化 或 排序+cdq分治+树状数组+平衡树 解析: 神题,考场不会,暴力骗40,

【BZOJ4553】[Tjoi2016&amp;Heoi2016]序列 cdq分治+树状数组

[BZOJ4553][Tjoi2016&Heoi2016]序列 Description 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化.现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可.注意:每种变化最多只有一个值发生变化.在样例输入1中,所有的变化是: 1 2 3 2 2 3 1 3 3 1

BZOJ2683: 简单题(CDQ分治 + 树状数组)

BZOJ2683: 简单题(CDQ分治 + 树状数组) 题意: 你有一个\(N*N\)的棋盘,每个格子内有一个整数,初始时的时候全部为\(0\),现在需要维护两种操作: 命令 参数限制 内容 \(1\ x\ y\ A\) \(1\le x,y \le N\),A是正整数 将格子\(x,y\)里的数字加上\(A\) \(2\ x1\ y1\ x2\ y2\) \(1\le x1\le x2\le N,1\le y1\le y2\le N\) 输出\(x1\ y1\ x2\ y2\)这个矩形内的数字

BZOJ1176---[Balkan2007]Mokia (CDQ分治 + 树状数组)

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1176 CDQ第一题,warush了好久.. CDQ分治推荐论文: 1 <从<Cash>谈一类分治算法的应用> 陈丹琦 2 <浅谈数据结构题的几个非经典解法>  许昊然 关于CDQ分治,两种要求:①操作不相互影响  ②可以离线处理 题目描述是有问题的,,初始时 全部为0,不是s 题意:二维平面内,两种操作,1 x y v ,位于(x,y)的值加上v...2 x1,

bzoj2716 [ Violet 3 ] --cdq分治+树状数组

树状数组打错调了一个小时... 对于点(x,y),其它点只会在他的左下.右下.左上.右上四个方向上.我们只需求在左下方向上就可以了,因为其他方向可以通过改变相对位置求得. 考虑cdq分治.先按x坐标排序,然后将区间[l,r]分为[l,mid],[mid+1,r],因为只求左下方向上的点,所以可以去掉绝对值:dis=x+y-(x'+y') 只需求x'+y'最大的点就可以了.求(X,Y)时将[l,mid]中x值小于X的点的x+y值在树状数组中更新,然后查询y小于Y的最大的x+y,更新答案. 代码:

HDU 5126 stars cdq分治+树状数组

题目链接:点击打开链接 题意: T个case n个操作 1. (x,y,z) 在三维平面的点上增加1 2.询问区间范围内的权值和. 思路: cdq分治套cdq分治,然后套树状数组即可.. #include <stdio.h> #include <iostream> #include <algorithm> #include <sstream> #include <stdlib.h> #include <string.h> #inclu

BZOJ 3648: 寝室管理( 点分治 + 树状数组 )

1棵树的话, 点分治+你喜欢的数据结构(树状数组/线段树/平衡树)就可以秒掉, O(N log^2 N). 假如是环套树, 先去掉环上1条边, 然后O(N log^2 N)处理树(同上); 然后再O(N log N)计算经过删掉边的路径数(在环上扫一遍, 数据结构维护). ------------------------------------------------------------------------- #include<cstdio> #include<cctype>

【BZOJ2870】最长道路tree 点分治+树状数组

[BZOJ2870]最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来往,所以每个路口i都有一个拥挤程度v[i],我们认为从路口s走到路口t的痛苦程度为s到t的路径上拥挤程度的最小值,乘上这条路径上的路口个数所得的积.现在请你求出痛苦程度最大的一条路径,你只需输出这个痛苦程度. 简化版描述: 给定一棵N个点的树,求树上一条链使得链的长度乘链上所有点中的最小权值所得的积