NOI 2016 选做
考虑将区间长度从小到大排序后必是选择一段区间。
直接双指针即可,用线段维护点被覆盖的信息,支持区间加,全局求最值。
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;
}
首先不难看出答案只能是 \(-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;
}