题目描述

一个原力网络可以看成是一个可能存在重边但没有自环的无向图。每条边有一种属性和一个权值。属性可能是R、G、B三种当中的一种,代表这条边上原力的类型。权值是一个正整数,代表这条边上的原力强度。原力技术的核心在于将R、G、B三种不同的原力融合在一起产生单一的、便于利用的原力。为了评估一个能源网络,JYY需要找到所有满足要求的三元环(首尾相接的三条边),其中R、G、B三种边各一条。一个三元环产生的能量是其中三条边的权值之积。
现在对于给出的原力网络,JYY想知道这个网络的总能量是多少。网络的总能量是所有满足要求三元环的能量之和。

输入

第一行包含两个正整数N、M。表示原力网络的总顶点个数和总边数。
接下来M行,每行包含三个正整数ui,vi,wi和一个字符ci。
表示编号ui和vi的顶点之间存在属性为ci权值为wi的一条边。
N≤50,000,M≤100,000,1≤?Wi≤10^6

输出

输出一行一个整数,表示这个原力网络的总能量模10^9+7的值

样例输入

4 6
1 2 2 R
2 4 3 G
4 3 5 R
3 1 7 G
1 4 11 B
2 3 13 B

样例输出

828


题解

根号分治+STL-map

看到这种根本没法写出什么玄学数据结构之类的,大概率就是根号分治了。

对于本题,由于边数只有 $m$ ,因此度数大于等于 $\sqrt m$ 的点只有 $O(\sqrt m)$ 个,我们称这样的点为大点,度数小于 $\sqrt m$ 的称为小点。

那么对于一个三元环:

如果三个点都是大点:这种情况下我们暴力枚举三个大点,求出是否有满足条件的三元环并加入到答案中即可。时间复杂度为 $O((\sqrt m)^3)=O(m\sqrt m)$ ;

如果三个点中有小点:这种情况下我们枚举每个小点和它的两条出边,判断这三个点是否有满足条件的三元环。此时,枚举第一条出边相当于枚举图中所有边,第二条出边是度数复杂度,而度数小于 $\sqrt m$ ,因此复杂度也是 $O(m\sqrt m)$ 的。注意这个过程需要保证不重不漏,因此只考虑枚举点为这三个点中编号最小的小点的答案。

那么如何判断是否有满足条件的三元环呢?我偷懒了使用STL-map判断两点之间有没有某颜色的边,复杂度上会多一个log。

时间复杂度 $O(m\sqrt m\log m)$ ,实际上跑得挺快的 然而在bz上还是倒数第一...

#include <map>
#include <cmath>
#include <cstdio>
#define N 50010
#define mod 1000000007
using namespace std;
typedef long long ll;
struct data
{
int x , y , z;
data() {}
data(int a , int b , int c) {x = a , y = b , z = c;}
bool operator<(const data &a)const {return x == a.x ? y == a.y ? z < a.z : y < a.y : x < a.x;}
};
map<data , ll> mp;
int head[N] , to[N << 2] , val[N << 2] , opt[N << 2] , next[N << 2] , cnt , d[N] , id[350] , tot;
char str[5];
inline void add(int x , int y , int v , int c)
{
to[++cnt] = y , val[cnt] = v , opt[cnt] = c , next[cnt] = head[x] , head[x] = cnt;
}
int main()
{
int n , m , si , i , j , k , x , y , z , t;
ll ans = 0;
scanf("%d%d" , &n , &m) , si = (int)sqrt(m);
for(i = 1 ; i <= m ; i ++ )
{
scanf("%d%d%d%s" , &x , &y , &z , str);
t = (str[0] == 'R' ? 1 : str[0] == 'G' ? 2 : 3);
add(x , y , z , t) , add(y , x , z , t) , d[x] ++ , d[y] ++ ;
(mp[data(x , y , t)] += z) %= mod , (mp[data(y , x , t)] += z) %= mod;
}
for(i = 1 ; i <= n ; i ++ )
if(d[i] >= si)
id[++tot] = i;
for(i = 1 ; i <= tot ; i ++ )
for(j = 1 ; j <= tot ; j ++ )
for(k = 1 ; k <= tot ; k ++ )
ans = (ans + mp[data(id[i] , id[j] , 1)] * mp[data(id[i] , id[k] , 2)] % mod * mp[data(id[j] , id[k] , 3)]) % mod;
for(i = 1 ; i <= n ; i ++ )
if(d[i] < si)
for(j = head[i] ; j ; j = next[j])
if(d[to[j]] >= si || to[j] > i)
for(k = next[j] ; k ; k = next[k])
if(opt[k] != opt[j] && (d[to[k]] >= si || to[k] > i))
ans = (ans + mp[data(to[j] , to[k] , 6 - opt[j] - opt[k])] * val[j] % mod * val[k]) % mod;
printf("%lld\n" , ans);
return 0;
}

【bzoj5206】[Jsoi2017]原力 根号分治+STL-map的更多相关文章

  1. BZOJ5206 [Jsoi2017]原力[根号分治]

    这是一个三元环计数的裸题,只是多了一个颜色的区分和权值的计算罢了. 有一种根号分治的做法(by gxz) 这种复杂度的证明特别显然,思路非常简单,不过带一个log,可以用unordered_map或者 ...

  2. BZOJ5206: [Jsoi2017]原力

    BZOJ5206: [Jsoi2017]原力 https://lydsy.com/JudgeOnline/problem.php?id=5206 分析: 比较厉害的三元环问题. 设立阈值,当点的度数大 ...

  3. BZOJ5206 JSOI2017原力(三元环计数)

    首先将完全相同的边的权值累加.考虑这样一种trick:给边确定一个方向,由度数小的连向度数大的,若度数相同则由编号小的连向编号大的.这样显然会得到一个DAG.那么原图的三元环中就一定有且仅有一个点有两 ...

  4. [JSOI2017]原力(分块+map(hash))

    题目描述 一个原力网络可以看成是一个可能存在重边但没有自环的无向图.每条边有一种属性和一个权值.属性可能是R.G.B三种当中的一种,代表这条边上 原力的类型.权值是一个正整数,代表这条边上的原力强度. ...

  5. bzoj 5206 [Jsoi2017]原力

    LINK:原力 一张无向图 这道题统计三元环的价值和.有重边但是无自环. 我曾经写过三元环计数 这个和那个题差不太多. 不过有很多额外操作 对于重边问题 我们把所有颜色相同的重边缩在一起 这样的话我们 ...

  6. [JSOI2017]原力

    题目大意: 一个$n(n\le5\times10^4)$个点,$m(m\le10^5)$条边的无向图.每条边有一个边权$w_i(w_i\le10^6)$和一个附加属性$t_i(t_i\in\{R,G, ...

  7. nowcoder 79F 小H和圣诞树 换根 DP + 根号分治

    设节点个数大于 $\sqrt n$ 的颜色为关键颜色,那么可以证明关键颜色最多有 $\sqrt n$ 个.对于每个关键颜色,暴力预处理出该颜色到查询中另一个颜色的距离和. 对于不是关键颜色的询问,直接 ...

  8. (转载)STL map与Boost unordered_map的比较

    原链接:传送门 今天看到 boost::unordered_map,它与 stl::map的区别就是,stl::map是按照operator<比较判断元素是否相同,以及比较元素的大小,然后选择合 ...

  9. CF804D Expected diameter of a tree 树的直径 根号分治

    LINK:Expected diameter of a tree 1e5 带根号log 竟然能跑过! 容易想到每次连接两个联通快 快速求出直径 其实是 \(max(D1,D2,f_x+f_y+1)\) ...

随机推荐

  1. Linux 用C语言实现简单的shell(1)

    发一波福利,操作系统的实验内容,大家可以借鉴一下,不过我的代码可能也存在一定的问题. 因为在一开始老师是一节一节课教的,当时并不知道后面还会用输入输出重定向,管道等一系列问题,我的兴趣也不在这个方面也 ...

  2. 20145226夏艺华 《Java程序设计》实验报告五

    实验五 Java网络编程及安全 实验内容 运行下载的TCP代码,结对进行 利用加解密代码包,编译运行代码,结对进行 集成代码,加密后通过TCP发送 结对伙伴:20145203 马超 实验步骤 (一)中 ...

  3. 2018.10.17校内模拟赛:T2神光

    题面:pdf 首先排序,二分,然后怎么判定是否可行. 最简单的思路是,dp[i][j][k],到第i个,用了j次红光,k次绿光,前i个点都选上了,是否可行.然后转移就行. 然后考试的时候就想到这了,往 ...

  4. Mysql:存储过程游标不进循环的原因详解

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本篇博客给刚接触存储过程的朋友做个引导作用,目的是解决游标不走循环 很多人发现他的游标,无论是嵌套循环还是单层 ...

  5. ubuntu的学习教程(常用操作)

    摘要 最近在学习linux,把自己学习过程中遇到的常用操作以及一些有助于理解的内容记录下来.我主要用的是ubuntu系统 命令提示符 '~' 这个是指用户的家目录,用户分为root用户和普通用户,ro ...

  6. 书写可维护的javascript

    内容介绍 编写可维护的代码很重要,因为大部分开发人员都花费大量时间维护他人代码. 1.什么是可维护的代码? 一般来说可维护的代码都有以下一些特征: 可理解性---------其他人可以接手代码并理解它 ...

  7. ython进阶06 循环对象

    这一讲的主要目的是为了大家在读Python程序的时候对循环对象有一个基本概念. 循环对象的并不是随着Python的诞生就存在的,但它的发展迅速,特别是Python 3x的时代,循环对象正在成为循环的标 ...

  8. [leetcode]三数之和

    三数之和 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以包含重复 ...

  9. 【shell 每日一练7】一键安装mysql5.7,以及密码及策略修改

    一.一键安装Mysql脚本 [root@uat01 ~]# cat InstallMysql01.sh #!/bin/bash #-- #旅行者-Travel #.安装wget yum -y inst ...

  10. [C++基础] tips

    1. 在g++ 中使支持C++11 https://askubuntu.com/questions/773283/how-do-i-use-c11-with-g This you can do by ...