CF762E Radio Stations

题目戳这里
我还以为是KDtree呢,但是KDtree应该也可以做吧。

这是一道数据结构好题。考虑到由于\(K \le 10\),所以我们用两个大vector——\(Left,Right\)\(Left_i\)记录频率为\(i\)的站,\(Right_i\)记录频率在\([i-K,i+K]\)之间的站。我们将\(Left_i\)里的站按其坐标来排序,\(Right_i\)里的站按其覆盖的左边界坐标排序。然后我们从左往右枚举\(Left_i\)里的元素。对于我们枚举的某个广播站\(x\),我们需要满足\(x \ge Lbound_y\),所以在\(Right_i\)中能与之配对的广播站肯定是一段前缀。但是还要满足\(x \le Rbound_y\),所以对于前缀我们需要用一个堆来维护\(Rbound_y \ge x\)\(y\)。然后查询按坐标建立一个树状数组即可。

#include<algorithm>
#include<iostream>
#include<set>
#include<vector>
#include<cstdio>
#include<cstdlib>
using namespace std;

#define lowbit(a) (a&-a)
typedef long long ll;
const int maxn = 100010,maxf = 10010;
int N,K,tree[maxn],disc[maxn],tot; ll ans;

inline void ins(int a,int b) { for (;a <= tot;a += lowbit(a)) tree[a] += b; }
inline int calc(int a) { int ret = 0; for (;a;a -= lowbit(a)) ret += tree[a]; return ret; }

inline int gi()
{
    char ch; int ret = 0,f = 1;
    do ch = getchar(); while (!(ch >= '0'&&ch <= '9')&&ch != '-');
    if (ch == '-') f = -1,ch = getchar();
    do ret = ret*10+ch-'0',ch = getchar(); while (ch >= '0'&&ch <= '9');
    return ret*f;
}

struct Node
{
    int x,r,f,lb;
    inline void read() { x = gi(); r = gi(); f = gi(); lb = x-r; }
    inline int rb() { return x+r; }
}sta[maxn];
vector <Node> Left[maxf],Right[maxf]; set < pair<int,int> > S;

inline bool cmp1(const Node &a,const Node &b) { return a.x < b.x; }
inline bool cmp2(const Node &a,const Node &b) { return a.lb < b.lb; }

int main()
{
    freopen("763E.in","r",stdin);
    freopen("763E.out","w",stdout);
    N = gi(); K = gi();
    for (int i = 1;i <= N;++i)
    {
        sta[i].read(); Left[sta[i].f].push_back(sta[i]);
        for (int j = max(1,sta[i].f-K);j <= 10000&&j <= sta[i].f+K;++j) Right[j].push_back(sta[i]);
    }
    for (int i = 1;i <= 10000;++i)
        sort(Left[i].begin(),Left[i].end(),cmp1),sort(Right[i].begin(),Right[i].end(),cmp2);
    for (int i = 1;i <= 10000;++i)
    {
        int n1 = Left[i].size(),n2 = Right[i].size(),now = 0; tot = 0;
        for (int j = n2-1;j >= 0;--j) disc[++tot] = Right[i][j].x;
        sort(disc+1,disc+tot+1); tot = unique(disc+1,disc+tot+1)-disc-1;
        for (int j = 0;j < n1;++j)
        {
            for (;now < n2&&Right[i][now].lb <= Left[i][j].x;++now)
            {
                int cor = lower_bound(disc+1,disc+tot+1,Right[i][now].x)-disc;
                S.insert(make_pair(Right[i][now].rb(),cor)); ins(cor,1);                
            }
            while (!S.empty()&&S.begin()->first < Left[i][j].x)
                ins(S.begin()->second,-1),S.erase(S.begin());
            int l = lower_bound(disc+1,disc+tot+1,Left[i][j].lb)-disc,r = upper_bound(disc+1,disc+tot+1,Left[i][j].rb())-disc-1;
            ans += calc(r)-calc(l-1);
        }
        while (!S.empty())
                ins(S.begin()->second,-1),S.erase(S.begin());
    }
    cout << ((ans-N)>>1) << endl;
    fclose(stdin); fclose(stdout);
    return 0;
}

转载于:https://www.cnblogs.com/mmlz/p/6456117.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值