P9514题解
Part 1:前言
CNOI 風味の強い日本名物!
这要放 CNOI 高低得给你套点超级数据结构,就题而言这道题还是挺不错的/kx。
Part 2:正文
下文中令
不妨从部分分入手。由于子任务 1 和该题正解做法关联性较低,故不再赘述,我们从子任务 2 开始看起。
我们先偷看一眼样例解释,发现第一种纪念品是一堆相邻最近点对距离为
因此我们有了一个
然后我们想起来了我们在噗叽组的时候学过的最大子矩形之类的题目,我们现在试图去枚举三个边界,然后考虑每个纪念品是否已经被包含在当前矩形里。每个纪念品都会对下一个边界产生一个不等式的限制条件,对这些不等式求交即可获得一个
我们试着再少扫一个边界,如果你像我一样只扫左上边界的话,你会获得一个没有前途的答辩
再少扫一个边界感觉就彻底没救了。我们现在试图把固定左端点扫一轮右端点的复杂度降低为
那么最后的做法就呼之欲出了。注意到对于每一个位置其实只需要有一个未被覆盖的就需要从链表中被删除。而在所有这样的纪念品中对每一列保留行号最靠右的即可,那么每次均摊的东西由
Part 3:代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,l,r) for(int i(l);i<=(r);++i)
#define per(i,r,l) for(int i(r);i>=(l);--i)
#define eb emplace_back
#define Debug(...) fprintf(stderr,__VA_ARGS__)
int read(){
int ans=0,flg=1;
char ch=getchar();
while(!isdigit(ch)){if(ch=='-')flg=-1;ch=getchar();}
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans*flg;
}
template<typename T>
void read(T &x){
x=0;T flg=1;
char ch=getchar();
while(!isdigit(ch)){if(ch=='-')flg=-1;ch=getchar();}
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
x*=flg;
}
template<typename T,typename... Args>
void read(T &x,Args &...args){read(x),read(args...);}
const int N=5e5+7,D=5e3+7;
int n,m,d,P[N],Q[N],R[N],S[N],lst[D][D*2];
bool visx[D],visy[D];
vector<int>vu[D*2];
struct List{
int pre[N],nxt[N],hd,tl,len;
void build(){for(int i=0;i<d;i++)pre[i]=i-1,nxt[i]=i+1;hd=0,tl=d-1,len=1e9;}
void del(int x){
int l=pre[x],r=nxt[x];
if(l!=-1)nxt[l]=r;
if(r!=d)pre[r]=l;
if(pre[r]==-1)hd=r;
if(nxt[l]==d)tl=l;
if(l!=-1&&r!=d)len=min(len,d-(r-l)+1);
}
}lis;
int main(){
read(n,m,d);
rep(i,1,n)read(P[i],Q[i]);
rep(i,1,m)read(R[i],S[i]);
rep(i,1,n)visx[P[i]]=1,visy[Q[i]]=1;
rep(i,1,m)lst[S[i]][R[i]]=R[i],lst[S[i]][R[i]+d]=R[i]+d;
rep(i,0,d-1)rep(j,1,2*D-1)lst[i][j]=max(lst[i][j-1],lst[i][j]);
int ans=1e9;
rep(l,0,d){
lis.build();int bg=0;
per(r,l-1+d,0)if(visx[r%d]){bg=r;break;}
rep(i,0,d-1)if(!visy[i]){
if(lst[i][l-1+d]<bg)lis.del(i);
else vu[lst[i][l-1+d]].eb(i);
}
rep(r,bg,l-1+d){
for(auto x:vu[r])lis.del(x);
ans=min(ans,(r-l+1)*min(lis.len,(lis.tl-lis.hd+1)));
vu[r].clear();
}
}
printf("%d\n",ans);
return 0;
}