洛谷 P7323 - [WC2021] 括号路径(启发式合并)
emmmm…………怎么评价这个题嘛。。。感觉纯论算法,此题根本谈不上难题,不过 WC 时候太智障只拿了个 48pts 就走人了。总之,技不如人,甘拜吓疯(
首先要注意到几件事情:
- 如果 \((x,y)\) 间存在合法的括号序列,那么 \((y,x)\) 之间也存在合法的括号序列,因为把一个路径反过来实际上相当于把括号序列翻转过来,并且左括号变右括号,右括号变左括号。
- 如果 \((x,y),(y,z)\) 之间存在合法的括号序列,那么 \((x,z)\) 之间也存在合法的括号序列。
我们将这两条综合在一起可得:存在合法括号序列的两点一定是若干个极大团的并。于是现在我们的任务就变为如何求这若干个团。
我们继续观察,又可得到一个性质:对于某个点 \(u\),如果存在某两个点 \(v,w\) 之间都存在连向 \(u\),左括号类型均为 \(i\) 的边,那么 \(v,w\) 之间肯定能互相到达,因为 \(v\to u\to w\) 就是形如 \(()\) 的合法路径。
如果我们将这个性质推广到一般团的情况,就有:对于同一个团中的两点 \(x,y\),如果存在某两个点 \(u,v\) 使得 \(u\) 与 \(x\) 之间、\(v\) 与 \(y\) 之间均有左括号类型为 \(i\) 的边,那么 \(u,v\) 就能互相到达,因为 \(x,y\) 本身就能互相到达,而在 \(x,y\) 的路径前面添一个 \(i\) 类型的左括号,后面添一个 \(i\) 类型的右括号,得到的仍是合法的括号序列。
这样一来我们就可以想出一个做法,先每个点单独成一个团,然后 \(n\) 开个 std::map 数组 \(mp_u\)。\(mp_{u,w}\) 表示以 \(u\) 为终点是否存在类型为 \(w\) 的边,如果有,那我们就记录第一次被访问的满足 \(v\) 与 \(u\) 之间存在类型为 \(w\) 的边的 \(v\)。然后每次新读入一条形如 \((u,v,w)\) 的边,我们就检查 \(mp_{v,w}\) 是否有值,如果有,那么说明 \(mp_{v,w},u\) 与 \(v\) 之间都存在类型为 \(w\) 的边,我们就将 \(mp_{v,w}\) 与 \(u\) 合并,否则我们就将 \(mp_{v,w}\) 设为 \(u\)。
然后考虑怎样合并两个集合。显然在合并以 \(u,v\) 为代表的两个集合的过程中,如果存在某个 \(w\) 使得 \(mp_{u,w},mp_{v,w}\) 都非零,那么意味着 \(mp_{u,w}\) 能够到达某个在 \(u\) 所代表的团中的点 \(x\),\(mp_{v,w}\) 能够到达某个在 \(v\) 所代表的团中的点 \(y\),而由于我们要将 \(u,v\) 所在的团合并成一个大团,所以 \(x,y\) 可以互相到达,这意味着 \(mp_{u,w},mp_{v,w}\) 也能互相到达,于是我们进一步合并 \(mp_{u,w},mp_{v,w}\)。否则如果某个值非零,不妨设 \(mp_{v,w}\) 非零,我们就令 \(mp_{u,w}=mp_{v,w}\),表示 \(mp_{v,w}\) 能够到达某个 \(u,v\) 合并形成的大团中的点。这样不断合并直到不能再合并中为止即可。
算下复杂度,对于每条边 \((u,v,w)\) 最多被合并一次,所以总共最多合并 \(m\) 次,而如果我们使用启发式合并,那么每个元素最多被合并 \(\log m\) 次。再加上 std::map 的复杂度,可知总复杂度为 \(m\log^2m\)。当然如果使用哈希表可将 std::map 的 \(\log\) 去掉,但懒得写了/cy
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=1;
while(!isdigit(c)){if(c=='-') neg=-1;c=getchar();}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
x*=neg;
}
const int MAXN=3e5;
int n,m,k,f[MAXN+5],siz[MAXN+5];
map<int,int> buc[MAXN+5];
queue<pii> q;
int find(int x){return (!f[x])?x:find(f[x]);}
void merge(int x,int y){
// printf("%d %d\n",x,y);
x=find(x);y=find(y);
if(x!=y){
if(siz[x]<siz[y]) swap(x,y);
ffe(it,buc[y]){
int col=it->fi,z=it->se;
if(buc[x][col]) q.push(mp(z,buc[x][col]));
else buc[x][col]=z;
} f[y]=x;siz[x]+=siz[y];
}
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++) siz[i]=1;
for(int i=1;i<=m;i++){
int u,v,w;scanf("%d%d%d",&u,&v,&w);
if(buc[v][w]) q.push(mp(u,buc[v][w]));
else buc[v][w]=u;
}
while(!q.empty()){
pii p=q.front();q.pop();
merge(p.fi,p.se);
} ll ans=0;
for(int i=1;i<=n;i++) if(!f[i]) ans+=1ll*siz[i]*(siz[i]-1)/2;
printf("%lld\n",ans);
return 0;
}
洛谷 P7323 - [WC2021] 括号路径(启发式合并)的更多相关文章
- 洛谷 P3201 [HNOI2009]梦幻布丁(启发式合并)
题面 luogu 题解 什么是启发式合并? 小的合并到大的上面 复杂度\(O(nlogn)\) 这题颜色的修改,即是两个序列的合并 考虑记录每个序列的\(size\) 小的合并到大的 存序列用链表 但 ...
- 【洛谷 P2764】 最小路径覆盖问题(最大流)
题目链接 首先有\(n\)条路径,每条路径就是一个点,然后尽量合并,答案就是点数-合并数. 套路拆点,源连入,出连汇,原有的边入出连. 最大流就是最大合并数,第一问解决. 然后怎么输出方案? 我是找到 ...
- 【CSP-S 2019】【洛谷P5658】括号树【dfs】【二分】
题目: 题目链接:https://www.luogu.org/problem/P5658?contestId=24103 本题中合法括号串的定义如下: () 是合法括号串. 如果 A 是合法括号串,则 ...
- 洛谷P2860 [USACO06JAN]冗余路径Redundant Paths(tarjan求边双联通分量)
题目描述 In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1. ...
- [洛谷P1730] 最小密度路径
类型:Floyd 传送门:>Here< 题意:定义一条路径密度 = 该路径长度 / 边数.给出一张$DAG$,现有$Q$次询问,每次给出$X,Y$,问$X,Y$的最小密度路径($N \le ...
- 洛谷 P1739 表达式括号匹配
题目链接https://www.luogu.org/problemnew/show/P1739 题目描述 假设一个表达式有英文字母(小写).运算符(+,—,*,/)和左右小(圆)括号构成,以“@”作为 ...
- 【洛谷】P1176: 路径计数2【递推】
P1176 路径计数2 题目描述 一个N×N的网格,你一开始在(1,1),即左上角.每次只能移动到下方相邻的格子或者右方相邻的格子,问到达(N,N),即右下角有多少种方法. 但是这个问题太简单了,所以 ...
- 洛谷 P2860 [USACO06JAN]冗余路径Redundant Paths 解题报告
P2860 [USACO06JAN]冗余路径Redundant Paths 题目描述 为了从F(1≤F≤5000)个草场中的一个走到另一个,贝茜和她的同伴们有时不得不路过一些她们讨厌的可怕的树.奶牛们 ...
- 洛谷P2860 [USACO06JAN]冗余路径Redundant Paths
题目描述 In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1. ...
随机推荐
- 剑指offer:JZ9 用两个栈实现队列
JZ9 用两个栈实现队列 描述 用两个栈来实现一个队列,使用n个元素来完成 n 次在队列尾部插入整数(push)和n次在队列头部删除整数(pop)的功能. 队列中的元素为int类型.保证操作合法,即保 ...
- HttpClient.PatchAsJsonAsync - dotnet/runtime 项目贡献小记
TL;DR 迫于 PatchAsJsonAsync 方法缺失,我给 dotnet/runtime 项目贡献了相关的 API,可惜要到 .NET7 才能用上. https://github.com/do ...
- 记一个非常诡异的关于 shared_ptr 的 bug
问题描述 今天写项目的时候遇见一个特别诡异的 bug,体现在在执行某条语句时,程序会莫名崩溃,并且给出的错误信息也非常难懂,只有一个malloc(): invalid size (unsorted)错 ...
- zlib开发笔记(四):zlib库介绍、编译windows vs2015x64版本和工程模板
前言 Qt使用一些压缩解压功能,介绍过libzip库编译,本篇说明zlib库.需要用到zlib的msvc2015x64版本,编译一下. 版本编译引导 zlib在windows上的mingw32 ...
- 第四单元博客总结——暨OO课程总结
第四单元博客总结--暨OO课程总结 第四单元架构设计 第一次UML作业 简单陈述 第一次作业较为简单,只需要实现查询功能,并在查询的同时考虑到性能问题,即我简单的将每一次查询的结果以及递归的上层结果都 ...
- 无网络下,配置yum本地源
1. 新建一个没有iso镜像文件的虚拟机: 2. 本地上传一个镜像文件(CentOS7的镜像),到虚拟机已创建的目录: 例如:上传一个镜像文件CentOS-7-x86_64-Everything-17 ...
- [CSP-S2021] 回文
链接: P7915 题意: 给出一个长度为 \(2n\) 的序列 \(a\),其中 \(1\sim n\) 每个数出现了 2 次.有 L,R 两种操作分别是将 \(a\) 的开头或末尾元素加入到初始为 ...
- Java设计模式——模板设计模式
模板设计模式 1.模板模式简介 模板模式(Template ):模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑 ...
- usb设备无法识别
之前用飞线用旧板子飞线连接了一个wifi模块到usb0口上,调试ok的,现在新设计的板子回来了,wifi模块是连接在usb2口上的,系统起来后发现wlan0不存在,用lsusb查看wifi模块的usb ...
- word-break-ii leetcode C++
Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each ...