Codeforces Round 906
tilian
代码很长 但是思路很清新
我们发现k=2 意思我们只用考虑sum[i]<=2的地方
不从天入手而是反而考虑这些个 sum[i]<=2 的地方
sum[i]2 这个地方被两个区间cover过 我们可以算出这两个区间的相交的<=2的数量+这两个区间<=1的数量
sum[i]1 这个地方被一个区间cover过 我们可以算出这个区间<=1的数量
这样你会发现 你只用O(n)的查询啦
答案就是max(sum[i]2的情况的最大值,sum[i]1的最大值和次大值) sum[i]==1的时候注意去重
PII check(int a,int b,int c,int d){
int l,r,len;
if(c >= a) {
if(d <= b) len = d-c+1,l=c,r=d;
else len = b-c+1,l=c,r=b;
}else {
if(b <= d) len = b-a+1,l=a,r=b;
else len = d-a+1,l=a,r=d;
}
return {l,r};
}
void solve(){
int n,m,k;cin>>n>>m>>k;
vector<PII>a(m+1);
vector<int>sum(n+2),sum1(n+2),sum2(n+2);
int qt=0;
for(int i=1;i<=m;i++){
int l,r;cin>>l>>r;
a[i]={l,r};
sum[l]++;
sum[r+1]--;
}
for(int i=1;i<=n;i++){
sum[i]+=sum[i-1];
if(sum[i]==0){
qt++;
}
}
// cout<<qt<<endl;
for(int i=1;i<=n;i++){
if(sum[i]==1)sum1[i]++;
if(sum[i]==2)sum2[i]++;
sum1[i]+=sum1[i-1];
sum2[i]+=sum2[i-1];
}
map<int,vector<PII>>mp;
for(int i=1;i<=n;i++)mp[i].resize(0);
for(int i=1;i<=m;i++){
auto [l,r]=a[i];
auto it=mp.lower_bound(l);
vector<int>d;
while(it!=mp.end()&&it->first<=r){
mp[it->first].push_back({l,r});
// cout<<it->first<<' '<<endl;
if(mp[it->first].size()>=3)d.push_back(it->first);
it++;
}
sort(all(d));
d.erase(unique(all(d)),d.end());
for(auto j:d){
mp.erase(j);
}
}
vector<int>ans1;
set<PII>st;
vector<int>ans2;
for(auto [pos,v]:mp){
if(v.size()==1){
auto [l,r]=v[0];
if(st.count({l,r}))continue;
st.insert({l,r});
ans1.push_back(sum1[r]-sum1[l-1]);
// cout<<"1:"<<pos<<' '<<sum1[r]-sum1[l-1]<<endl;
}else if(v.size()==2){
auto [l,r]=v[0];
auto [L,R]=v[1];
PII now=check(l,r,L,R);
ans2.push_back(sum2[now.second]-sum2[now.first-1]+sum1[r]-sum1[l-1]+sum1[R]-sum1[L-1]);
// cout<<"2:"<<pos<<' '<<ans2.back()<<endl;
}
}
int mx=0;
sort(all(ans1),greater<>());
for(int i=0;i<2&&i<ans1.size();i++)mx+=ans1[i];
if(ans2.size())cout<<max(mx,*max_element(all(ans2)))+qt<<endl;
else cout<<mx+qt<<endl;
}
什么东西会很少 往往就是出发点