题解:AT_abc424_f [ABC424F] Adding Chords
star_field · · 题解
AT_abc424_f
题目大意不过多赘述了。
首先可以在纸上画几个图,分成不交叉的情况和交叉的情况两种。
我们考虑把圆拆成一条链,发现:圆内没有交叉的,拆开后的线段要么无交集,要么一条线段被另一条完全包含;而圆内有交叉的,拆开后交叉的两条线段有交集但没有包含关系。
(图片顺序对应,多边形的边仅用于辅助)
对于拆开的链,我们可以用线段树维护,现在考虑如何判断是否为相交。
对于一条线段,如果它之内与它相交的线段的右端点的最大值大于此线段的右端点,或左端点最小值小于该线段左端点,则该两条线段在圆内相交。
我们可以维护一棵最大值线段树
code
#include<bits/stdc++.h>
#define ll long long
#define ls(x) (x<<1)
#define rs(x) ((x<<1)|1)
#define mid ((l+r)>>1)
#define il inline
using namespace std;
const ll N=1e6+5,INF=0x3f3f3f3f;
ll n,m,x,y,t[N<<2],t2[N<<2];
il void push_up1(ll x){
t[x]=max(t[ls(x)],t[rs(x)]);
}
il void push_up2(ll x){
t2[x]=min(t2[ls(x)],t2[rs(x)]);
}
il void build1(ll x,ll l,ll r){
if(l==r){
t[x]=0;
return;
}
build1(ls(x),l,mid);
build1(rs(x),mid+1,r);
push_up1(x);
}
il void build2(ll x,ll l,ll r){
if(l==r){
t2[x]=INF;
return;
}
build2(ls(x),l,mid);
build2(rs(x),mid+1,r);
push_up2(x);
}
il void update(ll x,ll s,ll l,ll r,ll p){
if(l==r){
t[x]=p;
t2[x]=p;
return;
}
if(s<=mid) update(ls(x),s,l,mid,p);
else update(rs(x),s,mid+1,r,p);
push_up1(x);
push_up2(x);
}
il ll query1(ll x,ll L,ll R,ll l,ll r){
if(L<=l&&R>=r){
return t[x];
}
ll res=0;
if(L<=mid) res=max(res,query1(ls(x),L,R,l,mid));
if(R>mid) res=max(res,query1(rs(x),L,R,mid+1,r));
return res;
}
il ll query2(ll x,ll L,ll R,ll l,ll r){
if(L<=l&&R>=r){
return t2[x];
}
ll res=INF;
if(L<=mid) res=min(res,query2(ls(x),L,R,l,mid));
if(R>mid) res=min(res,query2(rs(x),L,R,mid+1,r));
return res;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
build1(1,1,n);
build2(1,1,n);
while(m--){
cin>>x>>y;
if(x>y) swap(x,y);
ll L=x+1, R=y-1;
if(L<=R){
ll mn=query2(1,L,R,1,n);
ll mx=query1(1,L,R,1,n);
if(mn<x||mx>y){
cout<<"No\n";
}else{
cout<<"Yes\n";
update(1,x,1,n,y);
update(1,y,1,n,x);
}
}else{
cout<<"Yes\n";
update(1,x,1,n,y);
update(1,y,1,n,x);
}
}
return 0;
}