CF762E Radio stations

\(\texttt{Description}\)

CodeForces 题目链接

洛谷题目链接

  • \(n\) 个三元组 \((x_i,r_i,f_i)\),求满足以下条件的无序二元组 \((u,v)\) 个数:

    • \(|f_u-f_v|\le k\)

    • \(x_u-r_u\le x_v\le x_u+r_u\)

    • \(x_v-r_v\le x_u\le x_v+r_v\)

  • \(n\le 10^5\)\(k\le 10\)\(x_i,r_i\le 10^9\)\(f_i\le 10^4\)

\(\texttt{Solution}\)

先将所有三元组按照 \(r_i\) 从大到小排序,考虑用 \(r\) 小的去覆盖 \(r\) 大的,因为这样 \(r\) 大的一定能够覆盖到 \(r\) 小的。

然后枚举 \(n\) 个三元组。对于第 \(i\) 个三元组,问题转化为求 \(|f_j-f_i|\le k\)\(x_i-r_i\le x_j\le x_i+r_i\)\(j\) 的个数。注意到 \(k\le 10\),枚举每一种智商,对于每一种智商开一棵权值线段树,查询 \([x_i-r_i,x_i+r_i]\) 中数的个数。这样空间较大,无法接受,所以使用动态开点以及离散化策略。查完后再把当前三元组修改到权值线段树上。

这样不会多数少数,且时间复杂度为 \(\mathcal{O}(nk\log n)\),空间复杂度为 \(\mathcal{O}(n\log n)\),可以接受。

\(\texttt{Code}\)

实现细节:

  • 可以用指令集卡常。

  • 我用指针实现动态开点线段树,注意时刻判断节点是否为 nullptr(修改中就新建节点,查询中就返回 \(0\))。并且 CodeForces 的结构体指针初始化不为 nullptr,要写构造函数。

  • 离散化可以用 setmap 实现,节省码量。map 也可以用 unordered_map,但是遇到特意卡哈希的数据就不可行了(下同)。

  • 由于智商的值域较大,所以每种智商对应的动态开点线段树的根用 map 映射一下。

  • 查询的时候,判断一下当前智商中是否有值,可以用 find 实现,否则直接访问 map 会新建节点,带来更大的空间。

  • 不开 long long 见祖宗。

评测记录

$\texttt{Click for Code}$
//Orz treenology
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
#include<bits/stdc++.h>
#define N 100005
#define ls x->lson
#define rs x->rson
using namespace std;
int n,k,lsh;
long long ans;
set<int>s;
unordered_map<int,int>mp;
struct radio{
    int x,r,f;
    bool operator<(const radio&b)const{
        return r>b.r;
    }
}a[N];
struct node{
    int sum;
    node*lson,*rson;
    node(){
        sum=0;
        lson=rson=nullptr;
    }
};
map<int,node*>rt;
void up(node*&x){
    x->sum=0;
    if(ls!=nullptr){
        x->sum+=ls->sum;
    }
    if(rs!=nullptr){
        x->sum+=rs->sum;
    }
}
void modify(node*&x,int l,int r,int k,int v){
    if(x==nullptr){
        x=new node;
    }
    if(l^r){
        int m=(l+r)>>1;
        if(k<=m){
            modify(ls,l,m,k,v);
        }else{
            modify(rs,m+1,r,k,v);
        }
        up(x);
    }else{
        x->sum+=v;
    }
}
int query(node*x,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr){
        return x->sum;
    }
    int m=(l+r)>>1,ret=0;
    if(ls!=nullptr&&ql<=m){
        ret+=query(ls,l,m,ql,qr);
    }
    if(rs!=nullptr&&qr>m){
        ret+=query(rs,m+1,r,ql,qr);
    }
    return ret;
}
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i){
        scanf("%d%d%d",&a[i].x,&a[i].r,&a[i].f);
        s.insert(a[i].x);
        s.insert(a[i].x-a[i].r);
        s.insert(a[i].x+a[i].r);
    }
    for(int i:s){
        mp[i]=++lsh;
    }
    sort(a+1,a+1+n);
    for(int i=1,x,l,r;i<=n;++i){
        x=mp[a[i].x];
        l=mp[a[i].x-a[i].r];
        r=mp[a[i].x+a[i].r];
        for(int j=a[i].f-k;j<=a[i].f+k;++j){
            auto it=rt.find(j);
            if(it!=rt.end()){
                ans+=query(it->second,1,lsh,l,r);
            }
        }
        modify(rt[a[i].f],1,lsh,x,1);
    }
    printf("%lld\n",ans);
}

\(\texttt{Reference}\)

【题解】CF1045G AI Robots by ExplodingKonjac

posted @ 2023-03-05 20:19  lzyqwq  阅读(29)  评论(0)    收藏  举报