「学习笔记」 图的连通性-Summar Vacation Trainning Day2

学个锤子就是复习

Network

当新增一条边时,两个点之间的割边全都变为非割边。
于是大力树剖(
更简单的写法是缩点。
Code:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int MAXN=2e5+5;
const int MAXM=2e5+5;
int n,m,head[MAXN],dep[MAXN],top[MAXN],va[MAXN],dfn[MAXN],cnt,fa[MAXN],siz[MAXN],son[MAXN],val[MAXN],sum,q,kk,num;
bool pd[MAXN],vis[MAXM<<1];
struct SG{
	struct node{
		int l,r,sum;bool laz;
	}t[MAXN<<2];
	void pup(int p){t[p].sum=t[p<<1].sum+t[p<<1|1].sum;}
	void pdo(int p){
		if(!t[p].laz) return;
		t[p<<1].sum=0;t[p<<1].laz=1;
		t[p<<1|1].sum=0;t[p<<1|1].laz=1;
		t[p].laz=0;
	}
	void bui(int p,int l,int r){
		t[p].l=l;t[p].r=r;t[p].laz=0;t[p].sum=0;
		if(l==r){t[p].sum=va[l];return;} 
		int mid=(l+r)>>1;
		bui(p<<1,l,mid);bui(p<<1|1,mid+1,r);
		pup(p);
	}
	void modi(int p,int l,int r){
		if(t[p].l>=l&&t[p].r<=r){
			t[p].sum=0;t[p].laz=1;return;
		}
		pdo(p);
		int mid=(t[p].l+t[p].r)>>1;
		if(l<=mid) modi(p<<1,l,r);
		if(r>mid) modi(p<<1|1,l,r);
		pup(p);
	}
	int Sum(int p,int l,int r){
		if(t[p].l>=l&&t[p].r<=r) return t[p].sum;
		pdo(p);
		int mid=(t[p].l+t[p].r)>>1,tmp=0;
		if(l<=mid) tmp+=Sum(p<<1,l,r);
		if(r>mid) tmp+=Sum(p<<1|1,l,r);
		return tmp;
	}
}T;
struct ren{
	int nxt,to;
}a[MAXM<<1];
void add(int x,int y){
	a[++cnt].to=y;a[cnt].nxt=head[x];head[x]=cnt; 
}
void clear(){
	memset(vis,0,sizeof(vis));memset(pd,0,sizeof(pd));memset(head,0,sizeof(head));memset(dep,0,sizeof(dep));memset(val,0,sizeof(val));memset(son,0,sizeof(son));cnt=1;sum=0;num=0;
}
void dfs(int now,int f){
	siz[now]=1;
	for(int i=head[now];i;i=a[i].nxt){
		int v=a[i].to;
		if(dep[v]) continue;
		vis[i]=vis[i^1]=1;
		dep[v]=dep[now]+1;fa[v]=now;dfs(v,now);siz[now]+=siz[v];if(siz[v]>siz[son[now]]) son[now]=v;
	}
}
void dfs1(int now,int t){
	dfn[now]=++num;top[now]=t;pd[now]=1;
	if(son[now]) dfs1(son[now],t);
	for(int i=head[now];i;i=a[i].nxt){
		int v=a[i].to;
		if(dep[v]<dep[now]||v==son[now]||pd[v]) continue;
		dfs1(v,v);
	}
}
void dfs2(int now){
	pd[now]=1;
	for(int i=head[now];i;i=a[i].nxt){
		int v=a[i].to;
		if(dep[v]!=dep[now]+1||pd[v]) continue;
		dfs2(v);
		val[now]+=val[v];
	}
}
void calc(int x,int y){
	int tmp=0;
	while(top[x]!=top[y]){
		if(dep[top[x]]>dep[top[y]]) swap(x,y);
		tmp+=T.Sum(1,dfn[top[y]],dfn[y]);
		T.modi(1,dfn[top[y]],dfn[y]);
		y=fa[top[y]];
	}
	if(dfn[x]>dfn[y]) swap(x,y);
	tmp+=T.Sum(1,dfn[x]+1,dfn[y]);
	T.modi(1,dfn[x]+1,dfn[y]);
	sum-=tmp;
}
int main(){
	while(scanf("%d%d",&n,&m)){
		if(n==0&&m==0) break;
		clear();
		for(int i=1,x,y;i<=m;i++){
			scanf("%d%d",&x,&y);
			add(x,y);add(y,x);
		}
		dep[1]=1;
		dfs(1,-1);
		dfs1(1,1);
		for(int now=1;now<=n;now++){
			for(int i=head[now];i;i=a[i].nxt){
				int v=a[i].to;
				if(dep[v]>dep[now]||vis[i]) continue;
				val[now]++;val[v]--;
			}
		}
		memset(pd,0,sizeof(pd));
		dfs2(1);
		va[1]=0;
		for(int i=2;i<=n;i++){
			if(val[i]) va[dfn[i]]=0;
			else{va[dfn[i]]=1;sum++;}
		}
		T.bui(1,1,n);
		printf("Case %d:\n",++kk);
		scanf("%d",&q);
		while(q--){
			int x,y;scanf("%d%d",&x,&y);calc(x,y);printf("%d\n",sum);
		}
		printf("\n");
	}
	return 0;
}

Falling Sand Easy Version

将每块沙子向其能影响到的沙子连边之后缩点,可以发现是个 DAG。
那么记录有多少个入度为0的联通块即可。
Code:

#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=4e5+5;
int n,m,head[MAXN],cnt,st[MAXN],top,co[MAXN],num,tot,dfn[MAXN],low[MAXN],kk,in[MAXN],res;
vector<vector<int> > f;
vector<int> shu[MAXN];
char s[MAXN];
struct ren{
	int nxt,to;
}a[MAXN<<4];
void add(int x,int y){
	a[++cnt].to=y;a[cnt].nxt=head[x];head[x]=cnt;
}
void tj(int now){
	dfn[now]=low[now]=++tot;st[++top]=now;
	for(int i=head[now];i;i=a[i].nxt){
		int v=a[i].to;
		if(!dfn[v]){
			tj(v);low[now]=min(low[now],low[v]);
		}
		else if(!co[v]) low[now]=min(low[now],dfn[v]);
	}
	if(dfn[now]==low[now]){
		kk++;
		int op=0;
		do{
			op=st[top--];co[op]=kk;
		}while(op!=now);
	}
}
int main(){
	scanf("%d%d",&n,&m);
	f.resize(n+5);
	for(int i=0;i<=n;i++) f[i].resize(m+5);
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		for(int j=1;j<=m;j++){
			if(s[j]=='#') f[i][j]=++num,shu[j].push_back(i);
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(f[i][j]){
				if(j!=1){
					if(f[i][j-1]) add(f[i][j],f[i][j-1]);
					auto pp=upper_bound(shu[j-1].begin(),shu[j-1].end(),i);
					if(pp!=shu[j-1].end()){
						add(f[i][j],f[*pp][j-1]);
					}
				}
				if(j!=m){
					if(f[i][j+1]) add(f[i][j],f[i][j+1]);
					auto pp=upper_bound(shu[j+1].begin(),shu[j+1].end(),i);
					if(pp!=shu[j+1].end()){
						add(f[i][j],f[*pp][j+1]);
					}
				}
				if(i>1&&f[i-1][j]) add(f[i][j],f[i-1][j]);
					auto pp=upper_bound(shu[j].begin(),shu[j].end(),i);
					if(pp!=shu[j].end()){
						add(f[i][j],f[*pp][j]);
					}
			}
		}
	}
	for(int i=1;i<=num;i++) if(!dfn[i]) tj(i);
	for(int now=1;now<=num;now++){
		for(int i=head[now];i;i=a[i].nxt){
			int v=a[i].to;
			if(co[now]==co[v]) continue;
			in[co[v]]++;
		}
	}
	for(int i=1;i<=kk;i++){
		if(!in[i]) res++;
	}
	printf("%d",res);
	return 0;
}
posted @ 2022-07-04 22:07  StranGePants  阅读(24)  评论(0编辑  收藏  举报