洛谷 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. ...
随机推荐
- 【Java虚拟机11】线程上下文类加载器
前言 目前学习到的类加载的知识,都是基于[双亲委托机制]的.那么JDK难道就没有提供一种打破双亲委托机制的类加载机制吗? 答案是否定的. JDK为我们提供了一种打破双亲委托模型的机制:线程上下文类加载 ...
- Netty学习笔记(1)NIO三大组件
1. Channel channel 有一点类似于 stream,它就是读写数据的双向通道,可以从 channel 将数据读入 buffer,也可以将 buffer 的数据写入 channel,而之前 ...
- 你知道什么是JUC了吗?
多线程一直Java开发中的难点,也是面试中的常客,趁着还有时间,打算巩固一下JUC方面知识,我想机会随处可见,但始终都是留给有准备的人的,希望我们都能加油!!! 沉下去,再浮上来,我想我们会变的不一样 ...
- LeetCode:BFS/DFS
BFS/DFS 在树专题和回溯算法中其实已经涉及到了BFS和DFS算法,这里单独提出再进一步学习一下 BFS 广度优先遍历 Breadth-First-Search 这部分的内容也主要是学习了labu ...
- 基于JWT的Token身份验证
身份验证,是指通过一定的手段,完成对用户身份的确认.为了及时的识别发送请求的用户身份,我们调研了常见的几种认证方式,cookie.session和token. 1.Cookie cookie是 ...
- 好好编程BUAA_SE(组/团队) Scrum Meeting 博客汇总
好好编程BUAA_SE(组/团队) Scrum Meeting 博客汇总 一.Scrum Meeting 1. Alpha Alpha阶段 第一次Scrum Meeting Alpha阶段 第二次Sc ...
- echart3 力引导布局实现节点的提示和折叠
最近在项目中需要开发一个图表来显示人员的各种属性,类似于一种树形的结构进行显示数据.如果多个人员有同一个属性,那么需要将相同的属性进行连线,即关联起来.即形成一个关系图,由于我自身对echarts稍微 ...
- Noip模拟77 2021.10.15
T1 最大或 $T1$因为没有开$1ll$右移给炸掉了,调了一年不知道为啥,最后实在不懂了 换成$pow$就过掉了,但是考场上这题耽误了太多时间,后面的题也就没办法好好打了.... 以后一定要注意右移 ...
- 转帖:新版vivado2019.2新增增量综合功能
从 Vivado 2019.1 版本开始,Vivado 综合引擎就已经可以支持增量流程了.这使用户能够在设计变化较小时减少总的综合运行时间. Vivado IDE 和 Tcl 命令批处理模式都可以启用 ...
- eclipse配置Tomcat和Tomcat出现无效端口解决办法
一.eclipse配置Tomcat 1. 按图选择window-preferences 2在server处选择runtime environment . 3.点击右侧add,选择自己的Tomcat版本 ...