[USACO24OPEN] Grass Segments G 题解

考虑对于一个区间 [li,ri],最少重叠长度为 ki,怎样的区间 [lj,rj] 可以与前者产生贡献;首先 rjljki,在满足这个条件的情况下需要有 rjli+kiljriki,这里 表示合取,即 C++ 中的 and。正难则反,考虑用长度 ki 的区间数量减去 rj<li+ki 以及 lj>riki 的区间数量和;容易得知后两部分是不交的,可以分开计算。

统计这个数量这是一个经典的二维数点问题。直接将待处理的数组按照 k 降序排序,复制一份按照 rl 排序。扫前者的同时从后者里面把满足 rlk 的区间不断加入答案,用 __gnu_pbds::tree 插入元素、统计答案即可。可以参考代码实现。

放代码:

#include<bits/stdc++.h>
#include<bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
typedef pair<int,int> pii;
typedef tuple<int,int,int,int> tpi;
int main(){
  ios::sync_with_stdio(false);
  int n,p=0; cin>>n;
  vector<tpi> a(n),b;
  for(int i=0;i<n;i++){
    auto &[l,r,k,x]=a[i]; cin>>l>>r>>k,x=i;
  }
  sort(a.begin(),a.end(),[](tpi x,tpi y){
    return get<2>(x)>get<2>(y);
  });
  b=a,sort(b.begin(),b.end(),[](tpi x,tpi y){
    return get<1>(x)-get<0>(x)>get<1>(y)-get<0>(y);
  }); // 两种排序
  tree<pii,null_type,greater<>,rb_tree_tag,tree_order_statistics_node_update> L;
  tree<pii,null_type,less<>,rb_tree_tag,tree_order_statistics_node_update> R;
  vector<int> s(n);
  for(auto [l,r,k,x]:a){
    while(p<n&&get<1>(b[p])-get<0>(b[p])>=k)
      L.insert(make_pair(get<0>(b[p]),p)),R.insert(make_pair(get<1>(b[p]),p)),p++;
    // 加入可能成为答案的元素
    s[x]=L.size()-R.order_of_key(make_pair(l+k,0))-L.order_of_key(make_pair(r-k,n));
    // 使用 order_of_key 查排名,进行统计
  }
  for(int i:s)cout<<i-1<<'\n';
  return 0;
}
posted @   FFTotoro  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示