借用了逆十字的代码,然后加入了自己的一些理解。
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
#define PII pair<int,int>
// #define x first
// #define y second
vector<PII> op0[N],op1[N];
int n,D,t[N<<2],tg[N<<2];
void change(int k,int l,int r,int x,int y,int v)
{
if(x<=l&&r<=y){
t[k]+=v;tg[k]+=v;return;//懒惰标记
}
int mid=(l+r)>>1;
if(x<=mid) change(k<<1,l,mid,x,y,v);
if(y>mid) change(k<<1|1,mid+1,r,x,y,v);
t[k]=min(t[k<<1],t[k<<1|1])+tg[k];//+tg[k]其实就是把懒惰标记下传//更新父结点信息。
}
int ask(int k,int l,int r)
{
if(l==r) return l;
int mid=(l+r)/2;
//因为要找到一个结点t[k]=0。t[k]!=0;
if(tg[k]+t[k<<1]==t[k]){
return ask(k<<1,l,mid);
}
return ask(k<<1|1,mid+1,r);
}
int main()
{
scanf("%d%d",&n,&D);
int del=(1<<30)/D*D;
for(int i=1;i<=n;i++){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
x1+=del,x2+=del,y1+=del,y2+=del;
vector<PII> _x,_y;
if(x2-x1>=D){
_x.push_back({0,D-1});
}
else if((x2-1)%D>=x1%D){
_x.push_back({x1%D,(x2-1)%D});
}
else{
_x.push_back({x1%D,D-1});
_x.push_back({0,(x2-1)%D});
}
//这里后一个减一是为了防止 1-5 5-8被覆盖了两次,改成1-4,5-7就不会了。
if(y2-y1>=D){
//全部覆盖
_y.push_back({0,D-1});
}
else if((y2-1)%D>=y1%D){
//一段覆盖
_y.push_back({y1%D,(y2-1)%D});
}
else{
//两端覆盖
_y.push_back({y1%D,D-1});
_y.push_back({0,(y2-1)%D});
}
for(auto j:_x)
for(auto k:_y){
//分开op0是入边,op1是出边
op0[j.first].push_back(k);
op1[j.second+1].push_back(k);//这里加1是因为你取模放的时候减了1。
}
//这里处理其实x不太重要,重要的是y,不是说重要不重要,就是偏重。
}
for(int i=0;i<D;i++){
//更新覆盖区域
//入边。
for(auto j:op0[i]){
change(1,0,D-1,j.first,j.second,1);
}
// 出边
for(auto j:op1[i]){
change(1,0,D-1,j.first,j.second,-1);
}
//
if(t[1]==0){
puts("YES");
cout<<i<<" "<<ask(1,0,D-1)<<endl;return 0;
}
}
puts("NO");
} 
京公网安备 11010502036488号