zoukankan      html  css  js  c++  java
  • [省选联考 2021 A 卷] 支配

    给出个有向图。定义受支配集(D_v)表示从(1)出发到(v)必须经过的点。

    有一些询问,每次询问加入一条边之后(D_v)变化的个数。

    保证(1)可以到达所有点。

    (nle 3000,mle 2n,qle 2*10^4)


    其实直接套支配树板子就可以得到(O((n+m)qlg n))的做法。

    分析支配树的性质:一条在原图的边((u,v)),在支配树上:1. 如果为前向边或横插边,一定有(fa_v=LCA(u,v));3. 为后向边。

    考虑现在加入一条边((x,y)),新增的路径要经过((x,y))。如果这是后向边则没有影响,如果是横插边或前向边:记(lca=LCA(x,y))(rt o lca)为必经点。分析:

    1. 如果有路径经过((x,y)),然后经过((w,z))(w)(lca)的子树内,(z)不在(lca)的子树内;由以上的分析可得,(fa_z=LCA(w,z))。显然(LCA(w,z))(lca)的祖先。于是到达(z)之前仍然必经(rt o fa_z),没有影响。
    2. 所以能影响到的点在(lca)子树内。并且如果能到达点(z)(fa_z=lca),因为还是经过了(rt o fa_z),所以也没有变化。因此能影响到的点(z)(lca)子树内,满足(dep_z>dep_{lca}+1)

    进一步可以得到算法:从(y)出发遍历原图的边,要求不能经过(dep_z>dep_{lca}+1)的点,遍历到的点数就是答案。

    支配树可以(O(nm))预处理,一次询问遍历时间是(O(n+m))

    其实后面这个问题也和Day1T3有些相像,用类似的方法做:维护每个点开始能到达哪些点,按照(dep_z)从大往小排序,每次加入点(z),对于起点(s),如果存在边((y,z))满足(s)能到达(y),那么(z)可达;如果(z)可达,从(z)开始往后遍历。能搞到(O(nm))预处理,(O(1))(O(log n))(取决于求LCA时间复杂度)询问。


    下面写的是(O(nm+qlg n))的方法。

    using namespace std;
    #include <bits/stdc++.h>
    #define N 3005
    #define M 6005
    int n,m,Q;
    struct EDGE{
    	int to;
    	EDGE *las;
    };
    struct Graph{
    	EDGE e[M];
    	int ne;
    	EDGE *last[N];
    	void link(int u,int v){
    		e[ne]={v,last[u]};
    		last[u]=e+ne++;
    	}
    } G,T,F0,F1;
    int vis[N],BZ,p[N];
    int anc[N][N],sz[N],fa[N],hs[N],dep[N],top[N];
    bool cmp1(int x,int y){return sz[x]<sz[y];}
    void BFS(int ban){
    	static queue<int> q;
    	vis[1]=++BZ;
    	q.push(1);
    	while (!q.empty()){
    		int x=q.front();
    		q.pop();
    		for (EDGE *ei=G.last[x];ei;ei=ei->las)
    			if (ei->to!=ban && vis[ei->to]!=BZ){
    				vis[ei->to]=BZ;
    				q.push(ei->to);
    			}
    	}
    	for (int i=1;i<=n;++i)
    		anc[i][ban]=(vis[i]!=BZ);
    }
    void buildT(){
    	for (int i=1;i<=n;++i)
    		anc[i][1]=1;
    	for (int i=2;i<=n;++i)
    		BFS(i);
    	for (int j=1;j<=n;++j)
    		for (int i=1;i<=n;++i)
    			sz[j]+=anc[i][j];
    	for (int i=1;i<=n;++i)
    		p[i]=i;
    	sort(p+1,p+n+1,cmp1);
    	for (int i=1;i<=n;++i)
    		for (int j=1;j<i;++j)
    			if (anc[p[j]][p[i]] && !fa[p[j]])
    				fa[p[j]]=p[i];
    	for (int i=2;i<=n;++i)
    		T.link(fa[i],i);
    	for (int x=1;x<=n;++x)
    		for (EDGE *ei=T.last[x];ei;ei=ei->las)
    			if (sz[ei->to]>sz[hs[x]])
    				hs[x]=ei->to;
    	top[1]=1,dep[1]=0;
    	for (int i=n;i>=1;--i){
    		int x=p[i];
    		for (EDGE *ei=T.last[x];ei;ei=ei->las){
    			dep[ei->to]=dep[x]+1;
    			top[ei->to]=(hs[x]==ei->to?top[x]:ei->to);
    		}
    	}
    }
    int LCA(int u,int v){
    	while (top[u]!=top[v])
    		if (dep[top[u]]>dep[top[v]])
    			u=fa[top[u]];
    		else
    			v=fa[top[v]];
    	return dep[u]<dep[v]?u:v;
    }
    bool cmp2(int x,int y){return dep[x]>dep[y];}
    int d[N][N],f[N][N];
    void bfs(int v,int t,int d[],Graph &F){
    	static queue<int> q;
    	q.push(v);
    	d[v]=t;
    	while (!q.empty()){
    		int x=q.front();
    		q.pop();
    		for (EDGE *ei=F.last[x];ei;ei=ei->las)
    			if (!d[ei->to]){
    				d[ei->to]=t;
    				q.push(ei->to);
    			}
    	}
    }
    int query(int x,int y){
    	int lca=LCA(x,y);
    	if (x==y || lca==fa[y] || lca==y)
    		return 0;
    	return f[y][dep[lca]+2 +1];
    }
    int main(){
    	freopen("dominator.in","r",stdin);
    	freopen("dominator.out","w",stdout);
    //	freopen("in.txt","r",stdin);
    //	freopen("out.txt","w",stdout);
    	scanf("%d%d%d",&n,&m,&Q);
    	for (int i=1;i<=m;++i){
    		int u,v;
    		scanf("%d%d",&u,&v);
    		G.link(u,v);
    	}
    	buildT();
    	for (int i=1;i<=n;++i)
    		p[i]=i;
    	sort(p+1,p+n+1,cmp2);
    	++BZ;
    	for (int i=1;i<=n;++i){
    		int x=p[i];
    		d[x][x]=dep[x]+1;
    		for (EDGE *ei=F1.last[x];ei;ei=ei->las)
    			F0.link(ei->to,x);
    		for (EDGE *ei=G.last[x];ei;ei=ei->las)
    			if (vis[ei->to]==BZ)
    				F0.link(x,ei->to);
    			else
    				F1.link(ei->to,x);
    		for (int s=1;s<=n;++s){
    			if (vis[s]!=BZ) continue;
    			bool bz=0;
    			for (EDGE *ei=F1.last[x];ei && !bz;ei=ei->las)
    				if (d[s][ei->to])
    					bz=1;
    			if (bz)
    				bfs(x,dep[x]+1,d[s],F0);
    		}
    		vis[x]=BZ;
    		bfs(x,dep[x]+1,d[x],F0);
    	}
    	for (int s=1;s<=n;++s){
    		for (int i=1;i<=n;++i)
    			f[s][d[s][i]]++;
    		for (int i=n;i>=1;--i)
    			f[s][i]+=f[s][i+1];	
    	}
    	while (Q--){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		int ans=query(x,y);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    odbc 连接字符串
    25个国外优秀电子商务网站设计案例
    用css 添加手状样式,鼠标移上去变小手,变小手
    js如何获得FCKeditor控件的值
    导致Asp.Net站点重启的10个原因
    分享45款高质量的免费(X)HTML/CSS模板
    20110627 VisualSVN安装与配置(Delphi72010/VS2010)
    iBatis把一个表的sqlmap配置的多个xml中。
    ASP.NET State Service
    存储过程分页
  • 原文地址:https://www.cnblogs.com/jz-597/p/14661114.html
Copyright © 2011-2022 走看看