[IOI2018] seats 排座位
压缩状态思想很不错的
每次把原来的贡献减掉,新来的再加上
最多涉及10个点
注意:
1.去重
2.下标从0开始
3.线段树初始的最小值个数都是r-l+1
代码:
#include<bits/stdc++.h> #define reg register int #define il inline #define mid ((l+r)>>1) #define numb (ch^'0') using namespace std; typedef long long ll; il void rd(int &x){ char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } namespace Miracle{ const int N=1000000+5; const int inf=0x3f3f3f3f; int id[N],vis[N],sta[N],top; int pos[N][2]; int n,m,q; int num(int x,int y){ return (x-1)*m+y; } struct tr{ int mi,cnt; int mx; int ad; }t[4*N]; void pushup(int x){ t[x].mi=min(t[x<<1].mi,t[x<<1|1].mi); t[x].mx=max(t[x<<1].mx,t[x<<1|1].mx); t[x].cnt=t[x<<1].cnt*(t[x<<1].mi==t[x].mi)+t[x<<1|1].cnt*(t[x<<1|1].mi==t[x].mi); } void pushdown(int x){ if(!t[x].ad) return; t[x<<1].ad+=t[x].ad; t[x<<1].mi+=t[x].ad; t[x<<1].mx+=t[x].ad; t[x<<1|1].ad+=t[x].ad; t[x<<1|1].mi+=t[x].ad; t[x<<1|1].mx+=t[x].ad; t[x].ad=0; } void build(int x,int l,int r){ if(l==r){ t[x].cnt=1;return; } build(x<<1,l,mid); build(x<<1|1,mid+1,r); pushup(x); } void add(int x,int l,int r,int L,int R,int c){ if(L<=l&&r<=R){ t[x].ad+=c; t[x].mi+=c; t[x].mx+=c; if(t[x].mi==t[x].mx) t[x].cnt=r-l+1; return; } pushdown(x); if(L<=mid) add(x<<1,l,mid,L,R,c); if(mid<R) add(x<<1|1,mid+1,r,L,R,c); pushup(x); } int mv[4][2]={{+1,0},{-1,0},{0,+1},{0,-1}}; void wrk1(int x,int y,int c){ //cout<<" x y "<<x<<" "<<y<<" c "<<c<<endl; int mi=inf,cmi=inf; for(reg i=0;i<4;++i){ int dx=x+mv[i][0],dy=y+mv[i][1]; if(dx>=1&&dx<=n&&dy>=1&&dy<=m){ if(id[num(dx,dy)]<mi){ cmi=mi;mi=id[num(dx,dy)]; }else cmi=min(cmi,id[num(dx,dy)]); } } if(cmi<=id[num(x,y)]-1) { //cout<<" x y "<<x<<" "<<y<<" : "<<mi<<" "<<cmi<<endl; add(1,1,n*m,cmi,id[num(x,y)]-1,c); } } void wrk2(int x,int y,int c){ int mi=n*m+1; int dx=x-1,dy=y; if(dx>=1&&dx<=n&&dy>=1&&dy<=m){ mi=min(mi,id[num(dx,dy)]); } dx=x,dy=y-1; if(dx>=1&&dx<=n&&dy>=1&&dy<=m){ mi=min(mi,id[num(dx,dy)]); } //cout<<" x y "<<x<<" "<<y<<" mimimi "<<mi<<endl; if(id[num(x,y)]<=mi-1) add(1,1,n*m,id[num(x,y)],mi-1,c); } void sol(int x,int y,int c){ //cout<<" sol "<<x<<" "<<y<<" c "<<c<<endl; if(!vis[num(x,y)]) { sta[++top]=num(x,y); vis[num(x,y)]=1; wrk1(x,y,c);wrk2(x,y,c); } for(reg i=0;i<4;++i){ int dx=x+mv[i][0],dy=y+mv[i][1]; if(dx>=1&&dx<=n&&dy>=1&&dy<=m&&!vis[num(dx,dy)]){ vis[num(dx,dy)]=1; sta[++top]=num(dx,dy); wrk1(dx,dy,c);wrk2(dx,dy,c); } } } int main(){ rd(n);rd(m);rd(q); build(1,1,n*m); int x,y; for(reg i=1;i<=n*m;++i){ rd(x);rd(y); ++x;++y; pos[i][0]=x;pos[i][1]=y; id[num(x,y)]=i; } for(reg i=1;i<=n;++i){ for(reg j=1;j<=m;++j){ wrk1(i,j,1); wrk2(i,j,1); } } //cout<<t[1].mi<<" "<<t[1].mx<<" "<<t[1].cnt<<endl; int A,B; while(q--){ rd(A);rd(B); ++A;++B; top=0; x=pos[A][0],y=pos[A][1]; sol(x,y,-1); x=pos[B][0],y=pos[B][1]; sol(x,y,-1); while(top) vis[sta[top--]]=0; swap(id[num(pos[A][0],pos[A][1])],id[num(pos[B][0],pos[B][1])]); swap(pos[A][0],pos[B][0]); swap(pos[A][1],pos[B][1]); x=pos[A][0],y=pos[A][1]; sol(x,y,1); x=pos[B][0],y=pos[B][1]; sol(x,y,1); while(top) vis[sta[top--]]=0; int ans=0; if(t[1].mi==1) ans=t[1].cnt; printf("%d\n",ans); } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2019/2/10 17:53:31 */