题解 [IOI2018]Seats 排座位
题目链接
题意描述
你有一个
的座位表,每一格都有一位 ,编号给定,定义座位表的美妙度为所有编号为 的 座位集合且集合中的元素恰好构成一个矩形的 的个数, 次询问,每次询问交换两个 的座位,输出交换后座位表的美妙度。
这个问题很棘手,就算能迅速判定一个
观察一个矩形有什么性质:
(这不废话),因此矩形内仅有四角与矩形外的格子有两格是四连通的,它们是等价的,因此只需要保证左上角满足性质。
(这不也是废话),因此矩形外的格子最多有与矩形有一格四连通。
容易证明,以上两条性质
于是我们从两句废话中得到了矩形的关键性质。
我们由此考虑维护两类点(矩形左上角的点和矩形外使矩形出现拐角的点),设为黑点和白点,如果按照编号由
有了这两个信息,那么问题就很简单了,只要两类点在影响时间范围内
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define N 1000005
#define ls k<<1
#define rs k<<1|1
#define mid ((l+r)>>1)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define pii pair<int,int>
#define il inline
#define px OIer[i].x
#define py OIer[i].y
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;
il int read(){
int w=0,h=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')h=-h;ch=getchar();}
while(ch>='0'&&ch<='9'){w=w*10+ch-'0';ch=getchar();}
return w*h;
}
const int dx[]={1,-1,0,0},dy[]={0,0,1,-1};
struct Seat{int x,y,id;pii Sco[2];}OIer[N];
int n,m,q,op[4];bool rev;
vector<int>id[1005];
namespace SGT{
struct Data{int Min,Sum,Tag;}tr[N<<2];
void Pushup(int k){
tr[k].Min=min(tr[ls].Min,tr[rs].Min);
tr[k].Sum=tr[ls].Sum*(tr[ls].Min==tr[k].Min)+tr[rs].Sum*(tr[rs].Min==tr[k].Min);
}
void Update(int k,int v){tr[k].Min+=v;tr[k].Tag+=v;}
void Pushdown(int k){if(tr[k].Tag)Update(ls,tr[k].Tag),Update(rs,tr[k].Tag),tr[k].Tag=0;}
void Build(int k,int l,int r){
tr[k].Sum=r-l+1;
if(l==r)return;
Build(ls,l,mid);
Build(rs,mid+1,r);
}
void Modify(int k,int l,int r,int x,int y,int z){
if(l>y||r<x||x>y)return;
if(l>=x&&r<=y)return Update(k,z);
Pushdown(k);
if(x<=mid)Modify(ls,l,mid,x,y,z);
if(mid<y)Modify(rs,mid+1,r,x,y,z);
Pushup(k);
}
int Query(){return tr[1].Sum;}
}
using namespace SGT;
void Insert(int i,int j){
OIer[i].Sco[0]=mp(i,min(id[px-1][py],id[px][py-1])-1);
Modify(1,1,n*m,OIer[i].Sco[0].fi,OIer[i].Sco[0].se,j);
op[0]=id[px-1][py];op[1]=id[px][py-1];op[2]=id[px+1][py];op[3]=id[px][py+1];
sort(op,op+4);OIer[i].Sco[1]=mp(op[1],i-1);
Modify(1,1,n*m,OIer[i].Sco[1].fi,OIer[i].Sco[1].se,j);
}
signed main(){
n=read();m=read();q=read();
if(n>m)swap(n,m),rev=1;
for(int i=1;i<=n*m;i++){
int x=read()+1,y=read()+1;
if(rev)swap(x,y);
OIer[i]=(Seat){x,y,i};
}
Build(1,1,n*m);
sort(OIer+1,OIer+n*m+1,[](Seat x,Seat y){return(x.x==y.x)?x.y<y.y:x.x<y.x;});
for(int i=0;i<=m+1;i++)id[0].pb(inf),id[n+1].pb(inf);
for(int i=1;i<=n;i++)id[i].pb(inf);
for(int i=1;i<=n*m;i++)id[(i-1)/m+1].pb(OIer[i].id);
for(int i=1;i<=n;i++)id[i].pb(inf);
sort(OIer+1,OIer+n*m+1,[](Seat x,Seat y){return x.id<y.id;});
for(int i=1;i<=n*m;i++)Insert(i,1);
int pos[10];
while(q--){
int A=read()+1,B=read()+1,cnt=0,nx,ny;
pos[cnt++]=A;pos[cnt++]=B;
for(int i=0;i<4;i++){
nx=OIer[A].x+dx[i];ny=OIer[A].y+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m)pos[cnt++]=id[nx][ny];
nx=OIer[B].x+dx[i];ny=OIer[B].y+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m)pos[cnt++]=id[nx][ny];
}
sort(pos,pos+cnt);
cnt=unique(pos,pos+cnt)-pos;
for(int i=0;i<cnt;i++)Insert(pos[i],-1);
swap(OIer[A],OIer[B]);
swap(id[OIer[A].x][OIer[A].y],id[OIer[B].x][OIer[B].y]);
for(int i=0;i<cnt;i++)Insert(pos[i],1);
printf("%lld\n",Query());
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!