CF1368G

CF1368G - Shifting Dominoes

题目大意

给定一个被(1 imes 2)的骨牌(横向或者竖向)铺满的方格图

现在可以拿走一个骨牌,之后任意一个骨牌可以沿着其放置方向左右移动至多一步

求最终两个空位所在不同位置的方案数


分析

观察一个空位的移动

如果上/下/左/右边是一条骨牌,则可以移动到该骨牌所在的上/下/左/右边方格

将这个移动方式构成一个有向图(当然忽略反复横跳的情况)

大胆猜测此时你会发现它是 两片外向树森林,下面说明三个充分条件

1.跳跃的过程为((x,y) ightarrow (xpm 2,ypm 2)),显然(x+y)的奇偶性不变,故可以黑白染色分为两部分

2.一个点至多有一条入边:一个点的入边只能来自其所在骨牌的另一边

3.图中不存在环:

假设构成了一个环,此时这些边对应的骨牌围成一个不规则的环

从环的某一个角出发,向四周走,发现其余所有点总能完成一一匹配

也就是说,环内部包含的点个数为奇数,显然不存在这样的覆盖方案


答案计算

考虑移除一张骨牌生成两个点((x,y)),两个点分属于两片森林,并且可以向下走

不妨求出森林的( ext{dfs})序,此时问题变成了一个二维空间矩形覆盖问题

可以扫描线+线段树解决

const int N=2e5+10;

int n,m,d;
string s[N];
int I(int x,int y){ return (x-1)*m+y; }
ll ans;

vector <int> G[N];
int col(int u){ return ((u-1)%m+(u-1)/m)&1; }

void Link(int u,int v){ G[u].pb(v),ind[v]++; }
int ind[N],L[N],R[N],dfn;
void dfs(int u,int f){
	L[u]=++dfn;
	for(int v:G[u]) if(v!=f) dfs(v,u);
	R[u]=dfn;
}

// 线段树维护扫描过程中第二维未被覆盖的点个数
struct Node{
	int mi,x;
	Node operator + (const Node _) const {
		Node res;
		res.mi=min(mi,_.mi),res.x=0;
		if(mi==res.mi) res.x+=x;
		if(_.mi==res.mi) res.x+=_.x;
		return res;
	}
} tr[N<<2];
int t[N<<2];
void Down(int p){
	if(!t[p]) return;
	rep(i,p<<1,i+1) t[i]+=t[p],tr[i].mi+=t[p];
	t[p]=0;
}
void Upd(int p,int l,int r,int ql,int qr,int x){
	if(ql<=l && r<=qr) {
		t[p]+=x,tr[p].mi+=x;
		return;
	}
	Down(p);
	int mid=(l+r)>>1;
	if(ql<=mid) Upd(p<<1,l,mid,ql,qr,x);
	if(qr>mid) Upd(p<<1|1,mid+1,r,ql,qr,x);
	tr[p]=tr[p<<1]+tr[p<<1|1];
}

struct Update{
	int p,l,r,x;
	bool operator < (const Update __) const { return p<__.p; }
} U[N*2];
int C;

void Add(int x,int y){
	if(col(x)) swap(x,y);
	U[++C]=(Update){L[x],L[y],R[y],1};
	U[++C]=(Update){R[x]+1,L[y],R[y],-1};
}
void Build(int p,int l,int r){
	tr[p]=(Node){0,r-l+1};
	if(l==r) return;
	int mid=(l+r)>>1;
	Build(p<<1,l,mid),Build(p<<1|1,mid+1,r);
}

int main(){
	n=rd(),m=rd();
	rep(i,1,n) {
		cin>>s[i];
		rep(j,1,m) {
			if(s[i][j-1]=='U') if(i>1) Link(I(i-1,j),I(i+1,j));
			if(s[i][j-1]=='D') if(i<n) Link(I(i+1,j),I(i-1,j));
			if(s[i][j-1]=='L') if(j>1) Link(I(i,j-1),I(i,j+1));
			if(s[i][j-1]=='R') if(j<m) Link(I(i,j+1),I(i,j-1));
		}
	}
    // 获得dfs序
	rep(i,1,n*m) if(!ind[i]) dfs(i,0);
	rep(i,1,n) {
		rep(j,1,m) {
			if(s[i][j-1]=='U') Add(I(i,j),I(i+1,j));
			if(s[i][j-1]=='L') Add(I(i,j),I(i,j+1));
		}
	}
	Build(1,1,dfn);
	sort(U+1,U+C+1);
	int p=1;
	rep(i,1,dfn) {
		while(p<=C && U[p].p<=i) Upd(1,1,dfn,U[p].l,U[p].r,U[p].x),p++;
		int c=dfn-(tr[1].mi==0?tr[1].x:0);
		ans+=c;
	}
	printf("%lld
",ans);
}
原文地址:https://www.cnblogs.com/chasedeath/p/14752824.html