CF1109F Sasha and Algorithm of Silence's Sounds 题解

原题链接

大致题意

给定一个\(n\times m\)的网格图(\(n,m<=2000,n \times m<=2*10^5\)),每个格子上有个权值\(f_{i,j}\),保证\(f_{i,j}\)构成一个 \(1 ... n\times m\)的排列。问有多少区间满足这个权值在这个区间内的格子构成的连通块是一棵树。

Solution

考虑到若区间 \([l,r]\) 不满足,那么区间 \([l,r+1]\) 也一定不会满足条件,那么就可以利用 \(\text{Two Points}\)\(\text{Link-Cut Tree}\) 维护每个左端点最右边的没有环存在的右端点 \(r\)
考虑一颗树的判定:点数=边数 \(+1\) ,但是直接维护点数或者边数无法简单的进行查询,我们可以改变式子 点数 \(-\) 边数 \(=1\),我们可以利用线段树维护 点数 \(-\) 边数 的权值 ,又因为一定是一棵或者多棵树,所以一定有 点数 \(>\) 边数 ,所以线段树维护的权值最小值为 \(1\) ,而这恰好是我们需要查询的值。我们需要实现一棵支持区间加,区间求最小值出现次数的线段树。

Code

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int S=200005;
const int N=2005;
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
int n,m,nm,a[N][N],posx[S],posy[S],id[S];
int fa[S],son[S][2],sz[S],tagrev[S],sp[S],cntsp;
ll ans;int tcnt;bool flag;int nweg,tt;

inline void read(int &x)
{
	int f=1;char c;
	for(x=0,c=getchar();c<'0'||c>'9';c=getchar()) if(c=='-') f=-1;
	for(;c>='0'&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48); x*=f;
}
inline int mn(int _x,int _y){return _x<_y?_x:_y;}
inline int mx(int _x,int _y){return _x>_y?_x:_y;}
inline int ab(int _x){return _x<0?-_x:_x;}

inline int calc(int x,int y){return (x-1)*m+y;}
inline int getson(int x){return son[fa[x]][1]==x;}
inline bool isroot(int x){return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;}
inline void maintain(int x){
	tagrev[x]^=1;swap(son[x][0],son[x][1]);return ;
}
inline void pushdown(int x){
	if(tagrev[x]){
		if(son[x][0]) maintain(son[x][0]);
		if(son[x][1]) maintain(son[x][1]);
		tagrev[x]=0;
	}
	return ;
}
inline void pushup(int x){
	sz[x]=sz[son[x][0]]+sz[son[x][1]]+1;
	return ;
}
inline void rotate(int x){
	int y=fa[x];int z=fa[y];int k=getson(x);
	if(!isroot(y)) son[z][y==son[z][1]]=x;
	son[y][k]=son[x][k^1];if(son[x][k^1]) fa[son[x][k^1]]=y;
	son[x][k^1]=y;fa[y]=x;fa[x]=z;pushup(y);pushup(x);return ;
} 
inline void splay(int x){
	cntsp=0;int t=x;sp[++cntsp]=t;
	while(!isroot(t)) {t=fa[t];sp[++cntsp]=t;}
	while(cntsp){pushdown(sp[cntsp]);--cntsp;}
	
	for(int ff=0;(!isroot(x));rotate(x)){
		ff=fa[x];
		if(!isroot(ff)) rotate((getson(x)==getson(ff)?ff:x));
	}
	pushup(x);return ;
}
inline int Access(int x){
	int p;for(p=0;x;p=x,x=fa[x]){
		splay(x);son[x][1]=p;pushup(x);
	}
	return p;
}
inline int FindRoot(int x){
	Access(x);splay(x);
	while(1){
		pushdown(x);
		if(son[x][0]) x=son[x][0];
		else break;
	}
	splay(x);return x;
}
inline void makeroot(int x){
	Access(x);splay(x);maintain(x);return ;
}
inline int Link(int x,int y){
	if(FindRoot(x)==FindRoot(y)) return 0;
	makeroot(x);splay(x);fa[x]=y;
	pushup(y);Access(x);return 1;
}
inline int Cut(int x,int y){
	if(FindRoot(x)!=FindRoot(y)) return 0;
	makeroot(x);splay(x);Access(y);splay(y);
	if(fa[x]!=y||son[x][1]) return 0;
	fa[x]=son[y][0]=0;pushup(x);pushup(y);return 1;
}

struct Seg{
	int mnv[S*4],lazy[S*4],cnt[S*4];
	inline void pushup(int x){
		mnv[x]=mn(mnv[x<<1],mnv[x<<1|1]);cnt[x]=0;
		if(mnv[x<<1]==mnv[x]) cnt[x]+=cnt[x<<1];
		if(mnv[x<<1|1]==mnv[x]) cnt[x]+=cnt[x<<1|1];
		return ;
	}
	inline void pushdown(int x){
		if(lazy[x]==0) return ;
		lazy[x<<1]+=lazy[x];lazy[x<<1|1]+=lazy[x];
		mnv[x<<1]+=lazy[x];mnv[x<<1|1]+=lazy[x];
		lazy[x]=0;return ;
	}
	inline void update(int x,int l,int r,int ql,int qr,int v){
		if(ql>qr) return ;
		if(ql<=l&&r<=qr) {
			mnv[x]+=v;lazy[x]+=v;return ;
		}
		int mid=l+r>>1;pushdown(x);
		if(ql<=mid) update(x<<1,l,mid,ql,qr,v);
		if(qr>mid) update(x<<1|1,mid+1,r,ql,qr,v);
		pushup(x);return ;
	}
	inline int query(int x,int l,int r,int ql,int qr){
		if(ql<=l&&r<=qr){
			if(mnv[x]==1) return cnt[x];
			else return 0;
		}
		int mid=l+r>>1,rest=0;pushdown(x);
		if(ql<=mid) rest+=query(x<<1,l,mid,ql,qr);
		if(qr>mid) rest+=query(x<<1|1,mid+1,r,ql,qr);
		pushup(x);return rest;
	}	
	inline void build(int x,int l,int r){
		if(l==r){mnv[x]=0;cnt[x]=1;return ;}
		int mid=l+r>>1;
		build(x<<1,l,mid);build(x<<1|1,mid+1,r);
		pushup(x);return ;
	}
}T;
int main(){
	read(n);read(m);nm=n*m;
	T.build(1,1,nm);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			read(a[i][j]);
			posx[a[i][j]]=i;
			posy[a[i][j]]=j;
			id[a[i][j]]=calc(i,j);
		}
	}
	for(int i=1;i<=nm;i++) sz[i]=1;

	for(int i=1,j=0;i<=nm;i++){
		for(int k=j+1;k<=nm;k++){
			int nx=posx[k],ny=posy[k];
			flag=true;
			for(int u=0;u<4;u++){
				int tx=nx+dx[u];
				int ty=ny+dy[u];
				if(tx<1||tx>n||ty<1||ty>m) continue;
				if(a[tx][ty]<i||a[tx][ty]>k) continue;
				if(FindRoot(id[a[nx][ny]])==FindRoot(id[a[tx][ty]])) {
					flag=false;break;
				}
				Link(id[a[nx][ny]],id[a[tx][ty]]);
			}

			for(int u=0;u<4;u++){
				int tx=nx+dx[u];
				int ty=ny+dy[u];
				if(tx<1||tx>n||ty<1||ty>m) continue;
				if(a[tx][ty]<i||a[tx][ty]>k) continue;
				Cut(id[a[nx][ny]],id[a[tx][ty]]);
			}

			if(!flag) break;
			
			for(int u=0;u<4;u++)
			{
				int tx=nx+dx[u];
				int ty=ny+dy[u];
				if(tx<1||tx>n||ty<1||ty>m) continue;
				if(a[tx][ty]<i||a[tx][ty]>k) continue;
				nweg+=Link(id[a[tx][ty]],id[a[nx][ny]]);
			}
			j=k;
			T.update(1,1,nm,k,k,k-i+1);
			T.update(1,1,nm,k,k,-nweg);
		}
		ans+=T.query(1,1,nm,i,j);

		int nx=posx[i];int ny=posy[i];tt=0;
		for(int u=0;u<4;u++){
			int tx=nx+dx[u];int ty=ny+dy[u];
			if(tx<1||tx>n||ty<1||ty>m) continue;
			if(a[tx][ty]<i||a[tx][ty]>j) continue;
			if(Cut(id[a[tx][ty]],id[a[nx][ny]])){
				T.update(1,1,nm,a[tx][ty],j,1);
				++tt;
			}
		}
		nweg-=tt;
		T.update(1,1,nm,i,j,-1);
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2022-12-21 08:47  FireAspect  阅读(51)  评论(0)    收藏  举报