把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P7323 [WC2021] 括号路径

题面传送门

为了方便,我们仅保留\((v,u,-w)\)的反向边。

可以发现,如果某个点\(u\)\(v_1,v_2\)同时有相同边权的边,那么\((v_1,v_2)\)就是一个合法的点对。因此可以这样暴力扩展,用bitset优化,能过\(64\)分。

这个方法的问题在于没有用到双向边的性质。具体的,我们发现,如果\((u,v_1)\)是可达的,\((u,v_2)\)是可达的,那么\((v_1,v_2)\)也是可达的,因为路径双向。

则可以用并查集维护这个东西,然后对于每个联通块,统计连到外面的边。这里发现每种颜色的边只需要保留一条,因为之前已经都合并过了。所以用个能合并的东西维护就好了。

因为275307894a很懒,所以写了个启发式合并map,复杂度两个\(\log\),如果写线段树合并可以做到一个\(\log\)

code:

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n))
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=3e5+5,M=5e5+5,K=1e5+5,mod=998244353,Mod=mod-1,INF=2e9+7;const db eps=1e-7;mt19937 rnd(263082);
int n,m,k,x,y,z,fa[N],Si[N];ll Ans;unordered_map<int,int> f[N];
int GF(int x){return fa[x]^x?fa[x]=GF(fa[x]):x;}queue<pair<int,int>> Q;
#define fi first
#define se second
void Ins(int x,int y,int w){
	if(!f[x].count(w)) f[x][w]=y;
	else Q.push({y,f[x][w]});
}
int main(){
	int i,j;scanf("%d%d%d",&n,&m,&k);for(i=1;i<=m;i++)scanf("%d%d%d",&x,&y,&z),Ins(y,x,z);for(i=1;i<=n;i++) fa[i]=i;
	while(!Q.empty()){
		auto p=Q.front();Q.pop();if(GF(p.fi)==GF(p.se)) continue;
		int x=GF(p.fi),y=GF(p.se);f[x].size()<f[y].size()&&(swap(x,y),0);
		for(auto j:f[y]) Ins(x,j.se,j.fi);fa[y]=x;
	}
	for(i=1;i<=n;i++) Si[GF(i)]++;for(i=1;i<=n;i++) Ans+=1ll*Si[i]*(Si[i]-1)/2;printf("%lld\n",Ans);
}
posted @ 2023-01-17 08:14  275307894a  阅读(24)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end