NOI 2016 选做

[NOI2016] 区间

考虑将区间长度从小到大排序后必是选择一段区间。
直接双指针即可,用线段维护点被覆盖的信息,支持区间加,全局求最值。

Code
#include<bits/stdc++.h>
#define INF (0x3f3f3f3f)
using namespace std;
const int N=5e5+5;
int n,m;
struct seg{int l,r;}q[N];
int lsh[N*2],mx[N<<4],tag[N<<4];
bool cmp(seg a,seg b){return a.r-a.l<b.r-b.l;}
void update(int p){mx[p]=max(mx[p<<1],mx[p<<1|1]);}
void pushdown(int p){
	if(tag[p]==0)return;
	mx[p<<1]+=tag[p];
	mx[p<<1|1]+=tag[p];
	tag[p<<1]+=tag[p];
	tag[p<<1|1]+=tag[p];
	tag[p]=0;return;
}
void change(int p,int l,int r,int x,int y,int v){
	if(x<=l&&y>=r){tag[p]+=v;mx[p]+=v;return;}
	pushdown(p); 
	int mid=l+r>>1;
	if(x<=mid)change(p<<1,l,mid,x,y,v);
	if(y>mid)change(p<<1|1,mid+1,r,x,y,v);
	update(p);
}
int main(){
	//freopen("interval3.in","r",stdin);
	scanf("%d%d",&n,&m);		
	for(int i=1;i<=n;i++){
		scanf("%d%d",&q[i].l,&q[i].r);
		lsh[i*2-1]=q[i].l;
		lsh[i*2]=q[i].r;
	}
	sort(q+1,q+n+1,cmp);
	sort(lsh+1,lsh+2*n+1);
	int tot=unique(lsh+1,lsh+2*n+1)-lsh-1,ans=2*INF,j=1;
	for(int i=1;i<=n;i++){
		int ll=lower_bound(lsh+1,lsh+tot+1,q[i].l)-lsh;
		int rr=lower_bound(lsh+1,lsh+tot+1,q[i].r)-lsh;
		change(1,1,tot,ll,rr,1);
		if(mx[1]<m)continue;
		while(mx[1]>=m&&j<=i){
			int LL=lower_bound(lsh+1,lsh+tot+1,q[j].l)-lsh;
			int RR=lower_bound(lsh+1,lsh+tot+1,q[j].r)-lsh;
			change(1,1,tot,LL,RR,-1),j++;
		}
		j--;
		int LL=lower_bound(lsh+1,lsh+tot+1,q[j].l)-lsh;
		int RR=lower_bound(lsh+1,lsh+tot+1,q[j].r)-lsh;
		change(1,1,tot,LL,RR,1);
		ans=min(ans,(q[i].r-q[i].l)-(q[j].r-q[j].l));
	}
	printf("%d\n",ans==2*INF?-1:ans);
	return 0;
}

[NOI2016] 优秀的拆分

戳这里

[NOI2016] 网格

首先不难看出答案只能是 \(-1,0,1,2\)

\(-1\) : 剩下的点少于1个或者剩下两个相邻的点。
\(0\) :原图不连通
\(1\) : 原图存在割点。
\(2\) :剩下的情况。

答案最多是 \(2\) 很好证明,如果边角块没被叉掉那么就是 \(2\) ,否则叉掉后就会出现新角块。
发现图的规模很大 \(n,m \le 10^9\) 难点在于如何建图。
事实上有用的点只有叉点周围的 \(5 \times 5\) 的正方形,图的规模降到 \(O(24*c)\)
最难的在于如何判连通,手玩几组可以得到以下做法:
对于有用的点进行四连通bfs,给每个点染色,如果发现一个叉点周围的点颜色不同,那么就不连通。
否则求割点,注意割点必须满足既是图上的割点也是八连通点。

Code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+5,mod=1e6+7,MX=1e5;
int dx1[8]={0,1,1,1,0,-1,-1,-1};
int dy1[8]={-1,-1,0,1,1,1,0,-1};
int dx2[4]={0,1,0,-1};
int dy2[4]={1,0,-1,0};
int n,m,c,cnt,Rt;
struct{int x,y;}a[N],dy[N*24];
ll bh(int x,int y){return (x-1)*1LL*m+y;}
bool chk(int x,int y){return x>=1&&y>=1&&x<=n&&y<=m;}
vector<int>G[24*N];
int jb=0;
struct Map{
	int head[mod+5];ll to[mod+5];
	int val[mod+5],nxt[mod+5],tot;
	void ins(ll k,int x){
		int kk=k%mod;
		nxt[++tot]=head[kk];
		head[kk]=tot;
		to[tot]=k;val[tot]=x;
	}
	int qry(ll k){
		int kk=k%mod;
		for(int i=head[kk];i;i=nxt[i])
			if(to[i]==k)return val[i];
		return 0;
	}
	void Clear(){memset(head,tot=0,sizeof(head));}
}in,mp;
int dfn[N*24],low[N*24],col[N*24],num,colcnt;
bool cut[N*24],ok[N*24];
queue<int>S,Q;
void clean(int c){
	num=cnt=colcnt=0;
	in.Clear();mp.Clear();
	for(int i=1;i<=24*c;i++){
		G[i].clear();
		dfn[i]=low[i]=cut[i]=ok[i]=col[i]=0;
	}
}
void link(int ww){
	int x=a[ww].x,y=a[ww].y;
	for(int i=max(1,x-2);i<=min(n,x+2);i++)
		for(int j=max(1,y-2);j<=min(m,y+2);j++){
			if((i==x&&j==y)||in.qry(bh(i,j))!=0)continue;
			int now=mp.qry(bh(i,j));
			if(now==0){
				now=++cnt,mp.ins(bh(i,j),now),Q.push(now);
				dy[now].x=i,dy[now].y=j;
			}
			else{
				if(abs(i-x)<=1&&abs(j-y)<=1)ok[now]=1;
				continue;
			} if(abs(i-x)<=1&&abs(j-y)<=1)ok[now]=1;
			for(int k=0;k<4;k++){
				int fi=i+dx2[k],fj=j+dy2[k];
				if(!chk(fi,fj))continue;
				int to=mp.qry(bh(fi,fj));
				if(to==0)continue;
				G[now].push_back(to);G[to].push_back(now);
			}
		}
}
void tarjan(int u,int F){
	low[u]=dfn[u]=++num;int flag=0;
	for(auto v:G[u]){
		if(v==F)continue;
		if(!dfn[v]){
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
			if(dfn[u]<=low[v]){
				flag++;
				if(flag>1||u!=Rt)cut[u]=1;
			}
		}else low[u]=min(low[u],dfn[v]);
	}
}
bool check(){
	if(1LL*n*m-c>=3)return 1;
	if(1LL*n*m-c<=1)return 0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(in.qry(bh(i,j))==0)
				for(int k=0;k<4;k++){
					int fi=i+dx2[k],fj=j+dy2[k];
					if(!chk(fi,fj))continue;
					if(in.qry(bh(fi,fj))==0)return 0;
				}
	return 1;
}
void bfs(int st){
	S.push(st);
	while(S.size()){
		int u=S.front();S.pop();
		int ux=dy[u].x,uy=dy[u].y;
		col[u]=colcnt;
		for(int k=0;k<4;k++){
			int fx=ux+dx2[k],fy=uy+dy2[k];
			if(!chk(fx,fy))continue;
			int v=mp.qry(bh(fx,fy));
			if(v==0||col[v]!=0||in.qry(bh(fx,fy))>0)continue;
			S.push(v);col[v]=colcnt;jb++;
		}
	}
}
bool connected(){
	while(Q.size()){
		int u=Q.front();Q.pop();
		if(col[u])continue;
		colcnt++;bfs(u);
	}
	for(int k=1;k<=c;k++){
		int x=a[k].x,y=a[k].y,cnow=0;
		for(int i=max(1,x-2);i<=min(n,x+2);i++)
			for(int j=max(1,y-2);j<=min(m,y+2);j++){
				if((x==i&&y==j)||!chk(i,j)||in.qry(bh(i,j)))continue;
				int now=mp.qry(bh(i,j));
				if(cnow==0)cnow=col[now];
				else if(cnow!=col[now])return 0;
			}
	}
	return 1;
}
int work(){
	scanf("%d%d%d",&n,&m,&c);
	clean(c);
	for(int i=1;i<=c;i++){
		scanf("%d%d",&a[i].x,&a[i].y);
		in.ins(bh(a[i].x,a[i].y),i);
	}
	if(!check())return -1;
	for(int i=1;i<=c;i++)link(i);
	if(!connected())return 0;
	if(n==1||m==1)return 1;
	for(int i=1;i<=cnt;i++)if(!dfn[i])Rt=i,tarjan(i,0);
	for(int i=1;i<=cnt;i++)if(ok[i]&&cut[i])return 1;
	return 2;
}
int main(){
//	freopen("grid16.in","r",stdin);
//	freopen("my.out","w",stdout);
	int T;scanf("%d",&T);
	while(T--)printf("%d\n",work());
	return 0;
}
posted @ 2022-07-05 15:41  Isenthalpic  阅读(32)  评论(0编辑  收藏  举报