题目描述

一个原力网络可以看成是一个可能存在重边但没有自环的无向图。每条边有一种属性和一个权值。属性可能是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. 2017-2018-1 20155338 《信息安全系统设计基础》第5周加分项Mybash的实现

    2017-2018-1 20155338 <信息安全系统设计基础>第5周加分项Mybash的实现 使用fork,exec,wait实现mybash 一.fork函数 定义和理解:fork( ...

  2. 12、Java并发编程:阻塞队列

    Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...

  3. 如何在存储过程的IN操作中传递字符串变量

    原始SQL如下: SELECT MONTH(OrderTime) AS datetype, SUM(DeliveryCount) AS decount, Region FROM (SELECT dbo ...

  4. 关于Python的装饰器(1)

    Python的装饰器的概念,一直有点微妙.之前在StackOverflow上看过一篇感觉说明的很清楚的介绍: *A decorator must accept a function as an arg ...

  5. 九、EnterpriseFrameWork框架基础功能之消息管理

    记得阿朱在<走出软件作坊>一书中有一章讲客户提的需求太邪门了,鼠标键盘不太会用要程序员开发一个语音输入功能,还要系统中带类似QQ的功能:确实刚开始的客户的想法有点天真,但是随着信息化的越来 ...

  6. 04-JVM内存模型:直接内存

    1.1.什么是直接内存(Derect Memory) 在内存模型最开始的章节中,我们画出了JVM的内存模型,里面并不包含直接内存,也就是说这块内存区域并不是JVM运行时数据区的一部分,但它却会被频繁的 ...

  7. Windows下Mongodb安装部署

    1.下载安装包 mongodb-win32-x86_64-enterprise-windows-64-3.6.4.zip 解压 安装失败(当前环境windows server2012 R2):已验证可 ...

  8. AtCoder Grand Contest 026 D - Histogram Coloring

    一列中有两个连续的元素,那么下一列只能选择选择正好相反的填色方案(因为连续的地方填色方案已经确定,其他地方也就确定了) 我们现将高度进行离散化到Has数组中,然后定义dp数组 dp[i][j] 表示前 ...

  9. socket_tcp协议_loadrunner测试

    1.lrs_create_socket("socket0", "TCP", "RemoteHost=127.0.0.1:8888", Lrs ...

  10. XSS 注入检查点

    如果你有个论坛,一般你会很注意用户发帖的注入问题,往往这个地方不会被注入,因为开发特别照顾.原则上XSS都是用户输入的,但是许多边角还是容易忽略.枚举一些检查点. 分页 分页通用组件获取url,修改p ...