题目描述

了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发现她们已经结成了几个“群”.每只奶牛在吃草的时候有一个独一无二的位置坐标Xi,Yi(l≤Xi,Yi≤[1..10^9];Xi,Yi∈整数.当满足下列两个条件之一,两只奶牛i和j是属于同一个群的:
1.两只奶牛的曼哈顿距离不超过C(1≤C≤10^9),即lXi - xil+IYi - Yil≤C.
2.两只奶牛有共同的邻居.即,存在一只奶牛k,使i与k,j与k均同属一个群.
给出奶牛们的位置,请计算草原上有多少个牛群,以及最大的牛群里有多少奶牛

输入

第1行输入N和C,之后N行每行输入一只奶牛的坐标.

输出

仅一行,先输出牛群数,再输出最大牛群里的牛数,用空格隔开.

样例输入

4 2
1 1
3 3
2 2
10 10

样例输出

2 3


题解

为了练习Treap找到的这道略神的题

首先直接处理曼哈顿距离不是特别容易,我们可以把所有的点绕着原点逆时针旋转45°,这样原来的点$(x,y)$就变为了$(\frac{x-y}{\sqrt 2},\frac{x+y}{\sqrt 2})$,查询的区域变为了矩形范围,切比雪夫距离(横纵坐标差的绝对值最大值)不超过$\frac c{\sqrt 2}$。

然后约掉$\frac 1{\sqrt 2}$,就变为普通的矩形区域查询问题。

先将所有变换后的点按照横坐标排序,然后从左往右扫,将左面横坐标不满足条件的点删除。然后考虑连边:我们没有必要将所有在范围之内的点与当前点连边,只需要将当前点与第一个纵坐标比它大的点、第一个纵坐标比它小的点,如果满足条件就连边。

证明:使用数学归纳法

两个点之间使用这种方法是一定能够连上的。

如果k个点连上了,且纵坐标都比当前点大,并且横坐标满足条件,如果这种方法是不成立的,那么不妨设y1、y2,其中y1为纵坐标最接近当前点,y2为要连的点,我们要证的就是“当前点与y2有边,与y1没有边”是假命题。证明显然~

纵坐标比当前点小的时候同理。

于是k+1个点也能连上。命题得证。

回到题中,删点加点、查询前驱后继可以使用平衡树,维护连通性可以使用并查集。最后扫一遍每个点即可得到答案。

时间复杂度$O(n\log n)$。

事实上,STL的set比Treap还快~

Treap:

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <algorithm>
  4. #define N 100010
  5. using namespace std;
  6. struct data
  7. {
  8. int x , y;
  9. }a[N];
  10. typedef pair<int , int> pr;
  11. int l[N] , r[N] , rnd[N] , tot , root , f[N] , tmp , num[N];
  12. pr w[N];
  13. bool cmp(data a , data b)
  14. {
  15. return a.x < b.x;
  16. }
  17. void zig(int &k)
  18. {
  19. int t = l[k];
  20. l[k] = r[t] , r[t] = k , k = t;
  21. }
  22. void zag(int &k)
  23. {
  24. int t = r[k];
  25. r[k] = l[t] , l[t] = k , k = t;
  26. }
  27. void insert(int &k , pr x)
  28. {
  29. if(!k) k = ++tot , w[k] = x , rnd[k] = rand();
  30. else if(x < w[k])
  31. {
  32. insert(l[k] , x);
  33. if(rnd[l[k]] < rnd[k]) zig(k);
  34. }
  35. else
  36. {
  37. insert(r[k] , x);
  38. if(rnd[r[k]] < rnd[k]) zag(k);
  39. }
  40. }
  41. void del(int &k , pr x)
  42. {
  43. if(x == w[k])
  44. {
  45. if(!l[k] || !r[k]) k = l[k] + r[k];
  46. else if(rnd[l[k]] < rnd[k]) zig(k) , del(r[k] , x);
  47. else zag(k) , del(l[k] , x);
  48. }
  49. else if(x < w[k]) del(l[k] , x);
  50. else del(r[k] , x);
  51. }
  52. void pre(int k , pr x)
  53. {
  54. if(!k) return;
  55. else if(x < w[k]) pre(l[k] , x);
  56. else tmp = w[k].second , pre(r[k] , x);
  57. }
  58. void sub(int k , pr x)
  59. {
  60. if(!k) return;
  61. else if(x < w[k]) tmp = w[k].second , sub(l[k] , x);
  62. else sub(r[k] , x);
  63. }
  64. int find(int x)
  65. {
  66. return x == f[x] ? x : f[x] = find(f[x]);
  67. }
  68. int main()
  69. {
  70. int n , c , i , u , v , p = 1 , ans = 0 , mx = 0;
  71. scanf("%d%d" , &n , &c);
  72. for(i = 1 ; i <= n ; i ++ ) scanf("%d%d" , &u , &v) , a[i].x = u - v , a[i].y = u + v , f[i] = i;
  73. sort(a + 1 , a + n + 1 , cmp);
  74. for(i = 1 ; i <= n ; i ++ )
  75. {
  76. while(p < i && a[i].x - a[p].x > c) del(root , pr(a[p].y , p)) , p ++ ;
  77. tmp = 0 , pre(root , pr(a[i].y , i));
  78. if(tmp && a[i].y - a[tmp].y <= c) f[find(i)] = find(tmp);
  79. tmp = 0 , sub(root , pr(a[i].y , i));
  80. if(tmp && a[tmp].y - a[i].y <= c) f[find(i)] = find(tmp);
  81. insert(root , pr(a[i].y , i));
  82. }
  83. for(i = 1 ; i <= n ; i ++ ) num[find(i)] ++ ;
  84. for(i = 1 ; i <= n ; i ++ )
  85. if(num[i])
  86. ans ++ , mx = max(mx , num[i]);
  87. printf("%d %d\n" , ans , mx);
  88. return 0;
  89. }

STL-set:

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <set>
  4. #define N 100010
  5. using namespace std;
  6. struct data
  7. {
  8. int x , y;
  9. }a[N];
  10. typedef pair<int , int> pr;
  11. set<pr> s;
  12. set<pr>::iterator it;
  13. int f[N] , num[N];
  14. bool cmp(data a , data b)
  15. {
  16. return a.x < b.x;
  17. }
  18. int find(int x)
  19. {
  20. return x == f[x] ? x : f[x] = find(f[x]);
  21. }
  22. int main()
  23. {
  24. int n , c , i , u , v , p = 1 , ans = 0 , mx = 0;
  25. scanf("%d%d" , &n , &c);
  26. for(i = 1 ; i <= n ; i ++ ) scanf("%d%d" , &u , &v) , a[i].x = u - v , a[i].y = u + v , f[i] = i;
  27. sort(a + 1 , a + n + 1 , cmp);
  28. for(i = 1 ; i <= n ; i ++ )
  29. {
  30. while(p < i && a[i].x - a[p].x > c) s.erase(pr(a[p].y , p)) , p ++ ;
  31. it = s.upper_bound(pr(a[i].y , i));
  32. if(it != s.end() && it->first - a[i].y <= c) f[find(i)] = find(it->second);
  33. if(it != s.begin() && a[i].y - (--it)->first <= c) f[find(i)] = find(it->second);
  34. s.insert(pr(a[i].y , i));
  35. }
  36. for(i = 1 ; i <= n ; i ++ ) num[find(i)] ++ ;
  37. for(i = 1 ; i <= n ; i ++ )
  38. if(num[i])
  39. ans ++ , mx = max(mx , num[i]);
  40. printf("%d %d\n" , ans , mx);
  41. return 0;
  42. }

【bzoj1604】[Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 旋转坐标系+并查集+Treap/STL-set的更多相关文章

  1. bzoj 1604 [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居(set+并查集)

    Description 了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发现她们已经结成了几个“群”.每只奶牛在吃草的 时候有一个独一无二的位置坐标Xi,Yi( ...

  2. 【BZOJ】1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居(set+并查集+特殊的技巧)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1604 这题太神了... 简直就是 神思想+神做法+神stl.. 被stl整的我想cry...首先,, ...

  3. [BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的邻居

    [BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 试题描述 了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发 ...

  4. [BZOJ1604] [Usaco2008 Open] Cow Neighborhoods 奶牛的邻居 (queue & set)

    Description 了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发现她们已经结成了几个“群”.每只奶牛在吃草的时候有一个独一无二的位置坐标Xi,Yi(l ...

  5. [BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 (Treap+单调队列)

    题面 了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发现她们已经结成了几个"群".每只奶牛在吃草的时候有一个独一无二的位置坐标Xi,Yi( ...

  6. [BZOJ1604] [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居(好题)

    传送门 良心题解 #include <set> #include <cstdio> #include <iostream> #include <algorit ...

  7. 【BZOJ1604】[Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 Treap+并查集

    [BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 Description 了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000) ...

  8. BZOJ 1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居

    题目 1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 Time Limit: 5 Sec  Memory Limit: 64 MB Description ...

  9. BZOJ1604 & 洛谷2906:[USACO2008 OPEN]Cow Neighborhoods 奶牛的邻居——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=1604 https://www.luogu.org/problemnew/show/P2906#sub ...

随机推荐

  1. python基础教程总结12——数据库

    1. Python 数据库 API 很多支持SQL标准的数据库在Python中都有对应的客户端模块.为了在提供相同功能(基本相同)的不同模块之间进行切换(兼容),Python 规定了一个标准的 DB ...

  2. python基础教程总结6——类

    1. 如何定义一个类 在进行python面向对象编程之前,先来了解几个术语:类,类对象,实例对象,属性,函数和方法. 类是对现实世界中一些事物的封装,定义一个类可以采用下面的方式来定义: class  ...

  3. 手写IOC框架

    1.IOC框架的设计思路 ① 哪些类需要我们的容器进行管理 ②完成对象的别名和对应实例的映射装配 ③完成运行期对象所需要的依赖对象的依赖

  4. 无旋Treap【模板】P3369

    题目 详情见链接. 代码 #include<cstdio> #include<iostream> #define outd(x) printf("%d\n" ...

  5. 在Vue将第三方JS库封装为组件使用

    第三方JS库地址:https://github.com/inorganik/CountUp.js 使用NPM进行安装: npm install --save countup 根据官方回答,CountU ...

  6. python - 日期处理模块

    首先就是模块的调用,很多IDE都已经安装好了很多Python经常使用到的模块,所以我们暂时不需要安装模块了. ? 1 2 3 import datetime import time import ca ...

  7. C#数组删除元素

    一.C#数组删除元素 在C#中,只能在动态数组ArrayList类中对数组执行删除元素的操作.因为动态数组是一个可以改变数组长度和元素个数的数据类型. 示例: using System;using S ...

  8. mysql5.7.24 解压版安装步骤以及遇到的问题

    1.下载 https://dev.mysql.com/downloads/mysql/ 2.解压到固定位置,如D:\MySQL\mysql-5.7.24 3.添加my.ini文件 跟bin同级 [my ...

  9. destoon 短信发送函数及短信接口修改

    // $DT在common.inc.php中定义, $CACHE = cache_read('module.php'); $DT = $CACHE['dt'];  从缓存里读取网站配置信息. //$d ...

  10. MySQL中CONCAT()的用法

    MySQL中CONCAT()的用法 在日常开发过程中,特别是在书写接口的时候,经常会遇到字符串拼接的情况,比如在返回图片数据时,数据库里往往存储的是相对路径,而接口里一般是存放绝对地址,这就需要字符串 ...