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;
}

什么东西会很少 往往就是出发点

posted @ 2023-10-31 11:23  ycllz  阅读(28)  评论(0)    收藏  举报