【IOI2018】排座位

过来补常见套路题

对于前缀\([1,i]\)将它们染黑,考虑所有\((H+1) \times (W+1)\)\(2 \times 2\)小正方形,可以证明\([1,i]\)形成矩形充要条件是:

  1. 恰好\(4\)个有一个黑格的\(2 \times 2\)小正方形
  2. 没有任何一个有三个黑格的\(2 \times 2\)小正方形

同时可以发现有一个或三个黑格的小正方形总数不小于\(4\)

于是线段树维护所有前缀的有一个或三个黑格的小正方形个数,维护最小值及其个数。

初始化的时候可以线性建树。

时间复杂度\(O(HW+32Q\log HW)\)是常数非常大的做法,也许可以压一压,不会了。。

#include "seats.h"
#include<bits/stdc++.h>
using namespace std;
#define fp(i,l,r) for(register int (i)=(l);(i)<=(r);++(i))
#define fd(i,l,r) for(register int (i)=(l);(i)>=(r);--(i))
#define fe(i,u) for(register int (i)=front[(u)];(i);(i)=e[(i)].next)
#define mem(a) memset((a),0,sizeof (a))
#define O(x) cerr<<#x<<‘:‘<<x<<endl
const int MAXN=1e6+10;
struct node{
	int mn,v;
	inline node operator+(const node &b)const{
		if(mn==b.mn)return {mn,v+b.v};
		return mn<b.mn?(*this):b;
	}
}tr[MAXN<<2];
vector<int>mp[MAXN];
int H,W,n,R[MAXN],C[MAXN],tag[MAXN<<2];
#define lson o<<1
#define rson o<<1|1
inline void madd(int o,int v){
	tr[o].mn+=v;tag[o]+=v;
}
inline void pushdown(int o){
	if(!tag[o])return;
	madd(lson,tag[o]);madd(rson,tag[o]);tag[o]=0;
}
void add(int o,int l,int r,int ql,int qr,int v){
	if(l>=ql&&r<=qr){madd(o,v);return;}
	int mid=l+r>>1;pushdown(o);
	if(ql<=mid)add(lson,l,mid,ql,qr,v);
	if(qr>mid)add(rson,mid+1,r,ql,qr,v);
	tr[o]=tr[lson]+tr[rson];
}
inline void mdy(int x1,int x2,int x3,int x4,int coe){
	int a[5]={0,x1,x2,x3,x4};
	sort(a+1,a+5);
	if(a[1]<a[2])add(1,1,n,a[1],a[2]-1,coe);
	if(a[3]<a[4])add(1,1,n,a[3],a[4]-1,coe);
}
int sum[MAXN];
inline void mdy2(int x1,int x2,int x3,int x4){
	int a[5]={0,x1,x2,x3,x4};
	sort(a+1,a+5);
	if(a[1]<a[2])++sum[a[1]],--sum[a[2]];
	if(a[3]<a[4])++sum[a[3]],--sum[a[4]];
}
void build(int o,int l,int r){
	if(l==r){tr[o]={sum[l],1};return;}
	int mid=l+r>>1;
	build(lson,l,mid);build(rson,mid+1,r);
	tr[o]=tr[lson]+tr[rson];
}
void give_initial_chart(int HH,int WW,vector<int>RR,vector<int>CC){
	H=HH;W=WW;n=H*W;
	fp(i,1,n)R[i]=RR[i-1]+1,C[i]=CC[i-1]+1;
	fp(i,0,H+1)mp[i].resize(W+2,n+1);
	fp(i,1,n)mp[R[i]][C[i]]=i;
	fp(i,1,H+1)fp(j,1,W+1)mdy2(mp[i-1][j-1],mp[i-1][j],mp[i][j-1],mp[i][j]);
	fp(i,1,n)sum[i]+=sum[i-1];
	build(1,1,n);
}
inline void mdy(int x,int y,int coe){
	mdy(mp[x][y],mp[x-1][y],mp[x][y-1],mp[x-1][y-1],coe);
	mdy(mp[x][y],mp[x-1][y],mp[x-1][y+1],mp[x][y+1],coe);
	mdy(mp[x][y],mp[x][y-1],mp[x+1][y-1],mp[x+1][y],coe);
	mdy(mp[x][y],mp[x][y+1],mp[x+1][y],mp[x+1][y+1],coe);
}
int swap_seats(int a,int b){
	++a;++b;
	mdy(R[a],C[a],-1);mdy(R[b],C[b],-1);
	swap(R[a],R[b]);swap(C[a],C[b]);
	mp[R[a]][C[a]]=a;mp[R[b]][C[b]]=b;
	mdy(R[a],C[a],1);mdy(R[b],C[b],1);
	return tr[1].mn==4?tr[1].v:0;
}

【IOI2018】排座位

上一篇:Docker安装


下一篇:应用 |前端限制仅允许指定ip访问页面