CF762E Radio stations
\(\texttt{Description}\)
有 \(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,要写构造函数。 -
离散化可以用
set和map实现,节省码量。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);
}

浙公网安备 33010602011771号