「学习笔记」 图的连通性-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;
}
本文来自博客园,作者:{StranGePants},转载请注明原文链接:https://www.cnblogs.com/StranGePants/p/16444636.html