题解:P10763 [BalticOI 2024] Tiles
挺好想但是非常难写的一道题。。。
题目分析
显然我们可以扫描线。在从左往右扫的过程中若不合法的情况则输出此时的答案。
题目给的条件相当于:此时扫描到的任意一条线段长为偶数;一条线段加进来与踢出去的位置奇偶性相同。
于是可以维护两个 set<pair<int,int>>,分别存在偶数下标和奇数下标加进来的线段。但在加入时,可以将其与边上的线段合并。此时可以维护奇数线段的个数。删除同理。若加完或删完后奇数线段的个数大于
然后来统计答案。若此时两个 set 其中一个为空,说明不会出现交错的情况,否则当前不行。若奇偶性不同的 set 为空,则把答案更新为当前坐标减一;若奇偶性相同的 set 为空,则把答案更新为当前坐标。需要注意的是,这些操作应在加入删除线段之前之后都做一遍。
于是就做完了。显然
AC Code
跑得还挺快的啊。
#include<bits/stdc++.h>
//#include<bits/extc++.h>
//bool Mst;
using namespace std;
using ll=long long;
using ld=long double;
//#define int ll
using pii=pair<int,int>;
const int N=2e5+5;
vector<pii> seg[N];
int b[N],bc,cnt;
set<pii> st[2];
int len(pii x){return (x.second-x.first)&1;}
bool check(set<pii> &st,pii x)
{
auto it=st.lower_bound(x);
if(it!=st.end()&&it->first<=x.first&&it->second>=x.second) return 1;
if(it==st.begin()) return 0;
it--;
if(it->first<=x.first&&it->second>=x.second) return 1;
return 0;
}
bool in(set<pii> &st,pii x)
{
auto it=st.lower_bound(x);
if(it!=st.end()&&it->first>=x.first&&it->second<=x.second) return 1;
if(it==st.begin()) return 0;
it--;
if(it->first>=x.first&&it->second<=x.second) return 1;
return 0;
}
void insert(set<pii> &st,pii x)
{
auto it=st.lower_bound(x);
if(it!=st.end())
{
if(it->first==x.second) x.second=it->second,cnt-=len(*it),st.erase(*it);
}
it=st.lower_bound(x);
if(it!=st.begin())
{
it--;
if(it->second==x.first) x.first=it->first,cnt-=len(*it),st.erase(*it);
}
cnt+=len(x),st.insert(x);
}
void erase(set<pii> &st,pii x)
{
auto it=st.lower_bound(x);
if(it==st.end()||it->first>x.first) it--;
if(it->first<x.first)
{
pii y={it->first,x.first};
cnt+=len(y),st.insert(y);
}
if(it->second>x.second)
{
pii y={x.second,it->second};
cnt+=len(y),st.insert(y);
}
cnt-=len(*it),st.erase(*it);
}
pii p[N];
//bool Med;
signed main()
{
// cerr<<"Memory Size: "<<abs((&Med)-(&Mst))/1024.0/1024<<" MB\n";
// ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
int n,m,ans=0;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>p[i].first>>p[i].second,b[++bc]=p[i].first;
sort(b+1,b+bc+1),bc=unique(b+1,b+bc+1)-b-1;
for(int i=1;i<=n;i++) p[i].first=lower_bound(b+1,b+bc+1,p[i].first)-b;
p[0]=p[n];
for(int i=1;i<=n;i++)
{
if(p[i].first==p[i-1].first)
{
int le=min(p[i].second,p[i-1].second),ri=max(p[i].second,p[i-1].second);
seg[p[i].first].push_back({le,ri});
}
}
for(int i=1;i<=bc;i++)
{
int x=b[i]&1;
if(st[x].empty()) ans=b[i]-1;
if(st[!x].empty()) ans=b[i];
for(pii e:seg[i])
{
if((in(st[0],e)&&in(st[1],e))||check(st[!x],e))
{
cout<<ans<<"\n";
return 0;
}
if(check(st[x],e)) erase(st[x],e);
else insert(st[x],e);
}
if(st[x].empty()) ans=b[i]-1;
if(st[!x].empty()) ans=b[i];
if(cnt) break;
}
cout<<ans<<"\n";
return 0;
}