• LOJ3462. 「WC2021」括号路径


    一张图,给出若干个三元组((u,v,w)),表示有(u o v)的颜色为(w)的左括号和(v o u)的颜色为(w)的右括号。询问多少对((u,v),u<v)使得(u)(v)存在路径使得这个路径上的括号序合法。

    (nle 3*10^5,mle 6*10^5)


    在比赛最后一个小时前一直在想怎么前缀和不小于零……于是连暴力都不会写……

    后来忽然发现可以记(f_{u,v})表示(u)可以到(v),然后暴力扩展。估分32,实际水了48。

    比赛之后才发现这个东西是双向的,也就是说(f_{u,v}=f_{v,u})

    于是如果(f_{u,v}=1),可以把(u,v)看成等价类。

    用并查集+启发式合并维护搞出所有等价类即可。

    具体:把等价类缩点,并且记录这些点的每种颜色的入边。把点丢到一个队列里,操作某个点的时候,找到所有入边大于等于(2)的边,将这些边连向的点缩起来,然后丢到队列中。

    注意细节。


    using namespace std;
    #include <bits/stdc++.h>
    #define N 300005
    #define M 600005
    #define ll long long
    int n,m,k;
    int dsu[N];
    int getdsu(int x){return dsu[x]==x?x:dsu[x]=getdsu(dsu[x]);}
    map<int,vector<int> > e[N];
    set<int> b[N];
    int sz[N];
    queue<int> q;
    bool inq[N];
    vector<int> o[N]; 
    bool cmpo(int x,int y){return sz[x]>sz[y];}
    void merge(int x,int y){
    	for (auto i=e[y].begin();i!=e[y].end();++i){
    		auto t=&e[x][i->first];
    		for (auto j=i->second.begin();j!=i->second.end();++j)
    			t->push_back(*j);
    		if (t->size()>=2)
    			b[x].insert(i->first);
    	}
    	e[y].clear();
    	dsu[y]=x;
    	sz[x]+=sz[y];
    }
    void BFS(){
    	for (int i=1;i<=n;++i)
    		q.push(i),inq[i]=1;
    	while (!q.empty()){
    		int x=q.front();
    		q.pop();
    		inq[x]=0;
    		x=getdsu(x);
    		int cnt=0;
    		for (auto i=b[x].begin();i!=b[x].end();++i){
    			auto t=&e[x][*i];
    			for (auto j=t->begin();j!=t->end();++j)
    				o[cnt].push_back(*j);
    			cnt++;
    			for (int j=t->size();j>=2;--j)
    				t->pop_back();
    		}
    		b[x].clear();
    		static int bz[N],BZ;
    		for (int i=0;i<cnt;++i){
    			++BZ;
    			int mx=0;
    			for (int j=0;j<o[i].size();++j){
    				int y=getdsu(o[i][j]);
    				if (sz[y]>sz[mx]) mx=y;
    			}
    			for (int j=0;j<o[i].size();++j){
    				int y=getdsu(o[i][j]);
    				if (y==mx) continue;
    				merge(mx,y);
    			}
    			if (!inq[mx])
    				inq[mx]=1,q.push(mx);
    			o[i].clear();
    		}
    	}
    }
    int main(){
    	freopen("in.txt","r",stdin);
    //	freopen("out.txt","w",stdout);
    	scanf("%d%d%d",&n,&m,&k);	
    	sz[0]=-1;
    	for (int i=1;i<=n;++i)
    		dsu[i]=i;
    	for (int i=1;i<=m;++i){
    		int u,v,w;
    		scanf("%d%d%d",&u,&v,&w);
    		e[v][w].push_back(u);
    		if (e[v][w].size()==2)
    			b[v].insert(w);
    		sz[v]++;
    	}
    	BFS();
    	static int cnt[N];
    	ll ans=0;
    	for (int i=1;i<=n;++i)
    		cnt[getdsu(i)]++;
    	for (int i=1;i<=n;++i)
    		if (dsu[i]==i)
    			ans+=(ll)cnt[i]*(cnt[i]-1)>>1;
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    ROS 学习遇到的问题记录(持续更新)
    09.07 jQuery 随意整理
    JavaScript 随意整理3
    JavaScript 随意整理2
    css 随意整理 08.08
    html 随意整理
    vue day2
    vue day1
    【copy】必备之常用正则表达式 By 其他博主
    note.js 笔记第二课
  • 原文地址:https://www.cnblogs.com/jz-597/p/14390911.html
Copyright © 2020-2023  润新知