您的位置:首页 > 其它

【题解】Radio stations Codeforces 762E CDQ分治

2017-01-26 10:47 141 查看
虽然说好像这题有其他做法,但是在问题转化之后,使用CDQ分治是显而易见的

并且如果CDQ打的熟练的话,码量也不算大,打的也很快,思维难度也很小

没学过CDQ分治的话,可以去看看我的另一篇博客,是CDQ分治的入门教程

下面是正文:

首先整理一下条件:

每个点有三个属性,x,r,f

统计有多少对点i,j满足 min(ri,rj) >= |xi-xj| 且 |fi-fj| <= k,这样的点对被称作是“坏的”

对r值取min是个烦人的条件,于是我们把点按照r值从大到小排序,按照r值从大到小的顺序依次考虑每个点

这样对于每个点,我们只考虑它之前出现的点,也就是r值比他大的点,和他能不能组成“坏的”点对

这样的话,因为一个点i之前所有的点j的r值都比他大,所以 min(ri,rj) = ri

然后我们重新看一下问题:

按照指定的顺序依次加入点,每次加入一个点i,考虑它之前加入的所有点j,有多少个点满足 |xi-xj| <= ri 且 |fi-fj| <= k

再转化一下:

对于每个点i,考虑有多少个它之前的点j满足 xi-ri <= xj <= xi+ri 且 fi-k <= fj <= fi+k

我们把x和f这两个属性看做二维平面中的横纵坐标,问题就变成了:

向一个平面中添加一个点,查询指定矩形内点的个数

这是一个经典的三维偏序问题,可以用 线段树套线段树 或者 CDQ分治 来做

代码如下:

1 #include <iostream>
2 #include <cstring>
3 #include <algorithm>
4 #include <cstdio>
5 #include <cstdlib>
6 #include <cassert>
7 #include <cctype>
8 #include <cmath>
9 #include <vector>
10 #include <queue>
11 #include <set>
12 #include <map>
13
14 using namespace std;
15 typedef long long ll;
16 const int MAXN = 100010;
17 const int MAXF = 10020;
18
19 int n, k;
20
21 struct Item { // 每个点的信息
22     int r, x, f;
23     bool operator<( const Item &rhs ) const {
24         return r > rhs.r; // 按照r值排序
25     }
26 }item[MAXN];
27
28 inline int lowbit( int num ) { return num&(-num); }
29 namespace BIT { // 树状数组相关
30     int c[MAXF] = {0};
31     void add( int x, int v ) {
32         for( ; x <= MAXF-1; x += lowbit(x) )
33             c[x] += v;
34     }
35     int query( int x ) {
36         int sum = 0;
37         for( ; x; x -= lowbit(x) )
38             sum += c[x];
39         return sum;
40     }
41     int query( int l, int r ) {
42         return query(r) - query(l-1);
43     }
44     void clear( int x ) {
45         for( ; x <= MAXF-1; x += lowbit(x) )
46             c[x] = 0;
47     }
48 }
49
50 struct Query {
51     int type, x, y, w;
52     // type == 1 表示查询 type == 0 表示修改
53     // w 表示查询对答案的贡献,为1或-1
54     bool operator<( const Query &rhs ) const {
55         if( x == rhs.x ) return type < rhs.type;
56         return x < rhs.x;
57     }
58 }query[MAXN*5], tmp[MAXN*5]; int qidx = 0;
59
60 ll ans = 0;
61
62 void cdq( int L, int R ) { // cdq分治主过程
63     if( R-L <= 1 ) return;
64     int M = (L+R)>>1; cdq(L,M); cdq(M,R);
65     int p = L, q = M, o = L;
66     while( p < M && q < R ) {
67         if( query[p] < query[q] ) {
68             if( query[p].type == 0 ) BIT::add( query[p].y, 1 );
69             tmp[o++] = query[p++];
70         } else {
71             if( query[q].type == 1 ) ans += BIT::query( query[q].y ) * query[q].w;
72             tmp[o++] = query[q++];
73         }
74     }
75     while( p < M ) tmp[o++] = query[p++];
76     while( q < R ) {
77         if( query[q].type == 1 ) ans += BIT::query( query[q].y ) * query[q].w;
78         tmp[o++] = query[q++];
79     }
80     for( int i = L; i < R; ++i ) {
81         if( query[i].type == 0 ) BIT::clear( query[i].y );
82         query[i] = tmp[i];
83     }
84 }
85
86 int main() {
87     scanf( "%d%d", &n, &k );
88     for( int i = 0; i < n; ++i )
89         scanf( "%d%d%d", &item[i].x, &item[i].r, &item[i].f );
90     sort( item, item+n );
91     for( int i = 0; i < n; ++i ) {
92         Item &it = item[i]; // 转化为平面上的添加和查询问题
93         int x1 = it.x-it.r, y1 = max( it.f-k, 1 );
94         int x2 = it.x+it.r, y2 = it.f+k;
95         query[qidx++] = (Query){ 1, x1-1, y1-1, 1 };
96         query[qidx++] = (Query){ 1, x1-1, y2, -1 };
97         query[qidx++] = (Query){ 1, x2, y1-1, -1 };
98         query[qidx++] = (Query){ 1, x2, y2, 1 };
99         query[qidx++] = (Query){ 0, it.x, it.f, 0 }; // 修改的w值没有意义
100     }
101     cdq(0,qidx);
102     cout << ans << endl;
103     return 0;
104 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: