【JZOJ7074】集合
【JZOJ7074】集合
by AmanoKumiko
Description
现有 N 个集合Si,每个集合可以表示成两个闭区间的并。
Q 次询问,每次询问 l, r,求最小的 x 满足\(∀l≤i≤ r, x ∈ Si\)。
Input
第一行读入 N, Q。
接下来 N 行,每行 ai , bi , ci , di ,表示 \(Si = [ai , bi ] ∪ [ci , di ]\)。
接下来 Q 行,每行读入 l, r 表示询问。
Output
对于每个询问输出一个整数 x。如果不存在这样的 x ,输出”NO”。
Sample Input
3 3
1 4 8 10
7 9 3 5
8 10 5 9
1 2
2 3
1 3
Sample Output
3
5
8
Data Constraint
设 M 为所有 bi , di 的上限
1 ≤ N, Q ≤ 10^6,1 ≤ M ≤ 10^9
1 ≤ ai ≤ bi ≤ M,1 ≤ ci ≤ di ≤ M,1 ≤ l ≤ r ≤ n
Solution
x一定为si的其中一个左端点
设L,R为i向左边/右边扩展,使得当前左端点被连续包含能到的最远位置
将a,b,c,d放在一起排序
用线段树维护下标,在左端点查询/修改,在右端点删除
求出L,R后将L,R,l,r放在一起排序
L,R在左端点区间修改
l,r在左端点单点查询R
套路:对于贡献和查询为区间形式可放在一起排序,然后数据结构维护
Code
#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define inf 2147483647
#define N 1000010
#define ls x<<1
#define rs (x<<1)|1
int n,q,ans[N],MS,AT,BT,L1[N],R1[N],L2[N],R2[N];
struct node{int a,b,c,d;}s[N];
struct mode{int l,r,pos,kind,val;}ask[N],b[N*3];
struct point{int kind,x,pos;}a[N*4];
struct re{int val,pos;};
struct tree1{
int Min[N*4],p1[N*4],p2[N*4];
void modify(int x,int l,int r,int pos,int v){
if(l==r){Min[x]+=v;return;}
int mid=l+r>>1;
pos<=mid?modify(ls,l,mid,pos,v):modify(rs,mid+1,r,pos,v);
Min[x]=min(Min[ls],Min[rs]);
p1[x]=(Min[rs]<=Min[ls]?p1[rs]:p1[ls]);
p2[x]=(Min[ls]<=Min[rs]?p2[ls]:p2[rs]);
}
re q1(int x,int l,int r,int ll,int rr){
if(r<ll||l>rr)return (re){inf,inf};
if(l>=ll&&r<=rr)return (re){Min[x],p1[x]};
int mid=l+r>>1;
re ql=q1(ls,l,mid,ll,rr),qr=q1(rs,mid+1,r,ll,rr);
return qr.val<=ql.val?qr:ql;
}
re q2(int x,int l,int r,int ll,int rr){
if(r<ll||l>rr)return (re){inf,inf};
if(l>=ll&&r<=rr)return (re){Min[x],p2[x]};
int mid=l+r>>1;
re ql=q2(ls,l,mid,ll,rr),qr=q2(rs,mid+1,r,ll,rr);
return ql.val<=qr.val?ql:qr;
}
void build(int x,int l,int r){
p1[x]=r;p2[x]=l;
if(l==r)return;
int mid=l+r>>1;
build(ls,l,mid);build(rs,mid+1,r);
}
}t1;
struct tree2{
int Min[N*4],tag[N*4];
void modify(int x,int l,int r,int ll,int rr,int v){
if(r<ll||l>rr)return;
if(l>=ll&&r<=rr){Min[x]=min(Min[x],v);return;}
int mid=l+r>>1;
modify(ls,l,mid,ll,rr,v);modify(rs,mid+1,r,ll,rr,v);
}
int query(int x,int l,int r,int pos){
if(l==r)return Min[x];
int mid=l+r>>1;
if(pos<=mid)return min(Min[x],query(ls,l,mid,pos));
return min(Min[x],query(rs,mid+1,r,pos));
}
void build(){F(i,1,n*4)Min[i]=inf;}
}t2;
void read(int &x){
char s=getchar();
while(s<'0'||s>'9')s=getchar();
while('0'<=s&&s<='9')x=x*10+s-'0',s=getchar();
}
bool cmp1(point a,point b){return a.x<b.x||a.x==b.x&&a.kind>b.kind;}
bool cmp2(mode a,mode b){return a.l<b.l||a.l==b.l&&a.kind>b.kind;}
int main(){
freopen("set.in","r",stdin);
freopen("set.out","w",stdout);
read(n);read(q);
F(i,1,n){
read(s[i].a);read(s[i].b);read(s[i].c);read(s[i].d);
MS=max(MS,max(s[i].b,s[i].d));
if(s[i].a>s[i].c)swap(s[i].a,s[i].c),swap(s[i].b,s[i].d);
if(s[i].c<=s[i].b){
a[++AT]=(point){1,s[i].a,i};a[++AT]=(point){0,max(s[i].b,s[i].d),i};
}else{
a[++AT]=(point){1,s[i].a,i};a[++AT]=(point){0,s[i].b,i};
a[++AT]=(point){2,s[i].c,i};a[++AT]=(point){0,s[i].d,i};
}
L1[i]=R1[i]=L2[i]=R2[i]=i;
}
F(i,1,q)read(ask[i].l),read(ask[i].r),ask[i].pos=i,b[++BT]=ask[i];
sort(a+1,a+AT+1,cmp1);
t1.build(1,0,n+1);
F(i,1,AT){
if(a[i].kind){
re Q1=t1.q1(1,0,n+1,0,a[i].pos-1),Q2=t1.q2(1,0,n+1,a[i].pos+1,n+1);
if(!Q1.val)a[i].kind==1?L1[a[i].pos]=Q1.pos+1:L2[a[i].pos]=Q1.pos+1;
if(!Q2.val)a[i].kind==1?R1[a[i].pos]=Q2.pos-1:R2[a[i].pos]=Q2.pos-1;
t1.modify(1,0,n+1,a[i].pos,1);
}else t1.modify(1,0,n+1,a[i].pos,-1);
}
F(i,1,n){
if(s[i].c<=s[i].b){
b[++BT]=(mode){L1[i],R1[i],i,1,s[i].a};
}else{
b[++BT]=(mode){L1[i],R1[i],i,1,s[i].a};
b[++BT]=(mode){L2[i],R2[i],i,1,s[i].c};
}
}
sort(b+1,b+BT+1,cmp2);
t2.build();
F(i,1,BT){
if(b[i].kind)t2.modify(1,1,n,b[i].l,b[i].r,b[i].val);
else{
int Q=t2.query(1,1,n,b[i].r);
if(Q<inf)ans[b[i].pos]=(ans[b[i].pos]?min(ans[b[i].pos],Q):Q);
}
}
F(i,1,q)if(ans[i])printf("%d\n",ans[i]);else printf("NO\n");
return 0;
}