zoukankan      html  css  js  c++  java
  • CF639F Bear and Chemistry

    题面:https://www.luogu.com.cn/problem/CF639F
    题意:给一张无向图(不保证联通),每次选定一些点,
    并在图中加一些边,问加边后这些点能否在一个边双内。
    (n),(m),(sum)n1,(sum)m1(leq) (3e5)
    题解:
    显然,一个暴力的想法是每次建边后跑一次边双。
    复杂度(O(Q*(n+m)))
    考虑如何优化。发现每次询问时可能只需要几个点,但我们
    却对整张图跑了一次,不够优秀。
    考虑先对原图边双缩点,得到一个森林。
    每次询问,可以按照给出的点和边建出虚树,然后在新图上再跑边双。
    这里建虚树可能不好做,这里给出我的建树过程:
    1.将选中的点和新边连接的两点加入一个数组;
    2.将这些点按照dfs序排序(需要预先对森林的每个连通块做树剖,
    每次记录dfs序的sum无需清零),这样一个连通块内的点是
    数组里的连续一段;
    3.对于同一联通块的点,正常建虚树即可;对于不同连通块的点,
    先将上一个连通块的虚树建好(把栈清空),再建新连通块的虚树。

    注意:

    1.每次做完一定要清空;
    2.注意强制在线,建议到CF上查看此题的强制在线方式,本代码
    中去掉了强制在线,防抄袭~
    3.代码较长时,一定要多加调试,多进行验证输出。
    时间复杂度:(O((n+m)logn)),如果用st表求lca可以做到(O(n+m))
    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define re register int
    #define F(x,y,z) for(re x=y;x<=z;x++)
    #define FOR(x,y,z) for(re x=y;x>=z;x--)
    typedef long long ll;
    #define I inline void
    #define IN inline int
    #define C(x,y) memset(x,y,sizeof(x))
    #define STS system("pause")
    template<class D>I read(D &res){
    	res=0;register D g=1;register char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-')g=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch)){
    		res=(res<<3)+(res<<1)+(ch^48);
    		ch=getchar();
    	}
    	res*=g;
    }
    #define T e[k].to
    int n,m,Q,X,Y,R,_n,_m,sum,now;
    int d[303000],ned[303000],a[303000];
    struct Graph{
    	vector<int>v[303000];
    	int root[303000],dep[303000],id[303000],son[303000],siz[303000],top[303000],ma[303000];
    	int head[303000],tot;
    	int vis[303000],dfn[303000],low[303000],clr[303000],color,mill;
    	int sn;
    	stack<int>s;
    	struct E{
    		int to,nt;
    	}e[606000];
    	I addin(int x,int y){v[y].emplace_back(x);}
    	I add(int x,int y){
    		e[++tot].to=y;
    		e[tot].nt=head[x];
    		head[x]=tot;
    	}
    	I tarjan(int x,int fa){
    		dfn[x]=low[x]=++mill;
    		vis[x]=1;s.emplace(x);
    		for(re k=head[x];k!=-1;k=e[k].nt){
    			if(k==(fa^1))continue;
    			if(!dfn[T]){
    				tarjan(T,k);
    				low[x]=min(low[T],low[x]);
    			}
    			else if(vis[T])low[x]=min(low[x],dfn[T]);
    		}
    		if(dfn[x]==low[x]){
    			++color;
    			while(s.top()!=x)clr[s.top()]=color,vis[s.top()]=0,s.pop();
    			clr[x]=color;vis[x]=0;s.pop();
    		}
    	}
    	I D_1(int x,int fa,int depth,int Root){
    		ma[x]=fa;dep[x]=depth;son[x]=-1;root[x]=Root;siz[x]=1;
    		re maxi=-1;
    		for(auto p:v[x]){
    			if(p==fa)continue;
    			D_1(p,x,depth+1,Root);
    			siz[x]+=siz[p];
    			if(maxi<siz[p])maxi=siz[p],son[x]=p;
    		}
    	}
    	I D_2(int x,int fa,int topi){
    		top[x]=topi;id[x]=++sum;
    		if(son[x]!=-1)D_2(son[x],x,topi);
    		for(auto p:v[x]){
    			if(p==fa||p==son[x])continue;
    			D_2(p,x,p);
    		}
    	}
    	IN ques_lca(int x,int y){
    		while(top[x]!=top[y]){
    			if(dep[top[x]]<dep[top[y]])swap(x,y);
    			x=ma[top[x]];
    		}
    		if(dep[x]>dep[y])swap(x,y);
    		return x;
    	}
    	I build(){
    		tot=-1;C(head,-1);
    		F(i,1,m){
    			read(X);read(Y);add(X,Y);add(Y,X);
    		}
    		F(i,1,n)if(!dfn[i])tarjan(i,-1);
    		F(i,1,n)for(re k=head[i];k!=-1;k=e[k].nt)if(clr[i]!=clr[T])addin(clr[i],clr[T]);
    		F(i,1,color)if(!root[i])D_1(i,0,1,i),D_2(i,0,i);
    	}
    	I solve(){
    		sn=1;
    		F(i,1,now)if(!dfn[a[i]])tarjan(a[i],-1);
    		F(i,2,_n)
    			if(clr[d[i]]!=clr[d[1]]){
    				sn=0;
    				break;
    			}
    		if(sn)cout<<"YES"<<endl;
    		else cout<<"NO"<<endl;
    		F(i,1,now)head[a[i]]=-1,dfn[a[i]]=low[a[i]]=clr[a[i]]=ned[a[i]]=0,mill=color=0;
    	}
    }G,g;
    inline bool bbb(int x,int y){return G.id[x]<G.id[y];}
    int q[303000],r;
    int main(){
    	read(n);read(m);read(Q);sum=0;C(g.head,-1);
    	G.build();
    	F(t,1,Q){
    		read(_n);read(_m);sum=0;g.tot=-1;
    		F(i,1,_n){
    		    read(d[i]);d[i]=G.clr[d[i]];if(!ned[d[i]])ned[d[i]]=1,a[++sum]=d[i];
    		}
    		F(i,1,_m){
    			read(X);read(Y);X=G.clr[X];Y=G.clr[Y];
    			g.add(X,Y);g.add(Y,X);
    			if(!ned[X])ned[X]=1,a[++sum]=X;
    			if(!ned[Y])ned[Y]=1,a[++sum]=Y;
    		}
    		sort(a+1,a+1+sum,bbb);r=0;now=sum;
    		F(i,1,sum){
    			if(!r||G.root[q[r]]!=G.root[a[i]]){
    				while(r>1)g.add(q[r],q[r-1]),g.add(q[r-1],q[r]),r--;
    				q[r=1]=G.root[a[i]];
    				if(!ned[G.root[a[i]]])ned[G.root[a[i]]]=1,a[++now]=G.root[a[i]];
    				else continue;
    			}
    			re lca=G.ques_lca(q[r],a[i]);
    			while(G.id[q[r]]>G.id[lca]){
    				if(G.id[q[r-1]]>G.id[lca])g.add(q[r-1],q[r]),g.add(q[r],q[r-1]),r--;
    				else g.add(lca,q[r]),g.add(q[r],lca),q[r]=lca,a[++now]=lca;
    			}
    			q[++r]=a[i];
    		}
    		while(r>1)g.add(q[r],q[r-1]),g.add(q[r-1],q[r]),r--;
    		g.solve();
    	}
    	return 0;
    }
    
  • 相关阅读:
    php学习之Model类
    PHP学习之图像处理-水印类
    PHP学习之文件上传类
    windows 安装gitea
    下载安装office2019
    第6章 互联网的那些事儿
    第五章 了解你的用户
    第四章 关于测试的一些思考
    第三章 web设计原则:
    第二章 编程之道
  • 原文地址:https://www.cnblogs.com/Purple-wzy/p/12108987.html
Copyright © 2011-2022 走看看