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

虽然说好像这题有其他做法,但是在问题转化之后,使用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 }

 

posted @ 2017-01-26 10:47  mlystdcall  阅读(959)  评论(0编辑  收藏  举报