BZOJ 1604: [Usaco2008 Open]Cow Neighborhoods
来源:互联网 发布:中国人口流动数据 编辑:程序博客网 时间:2024/04/29 09:03
4W
感觉是神题
2点坐标距离为:
|x1 - x2| + |y1 - y2|
如果将一个点改为(x+y,x-y) 那么2点的距离就变为
max (|x1 - x2| , |y1 - y2|)
也就是说,更改过的新坐标距离只要看其中一个坐标的差是否有C那么多就行了。
(证明略……自己分类枚举下就知道是对的了…… 但是不看题解我打死我,也想不到这样优化情况)
如果坐标按照x排序后,可以用deque来得到一个区间的x坐标的差都在c以内(队尾x - 队头x <= C 否则队头元素出来)
下面就是要快速判断y坐标是否合法了,在这里我当时纠结了不短时间,查了别人的题解才知道怎么办。
当前队列最后一个元素为p0 目前队列里的元素的x坐标都是合法的,找一个y坐标比p0.y小一点点的,和一个y坐标比p0.y大一点点的2个坐标。判断他们的坐标差是否
合法,然后合法就丢到并查集里去(其中一次WA的检查发现并查集写瑕疵了……我好弱啊)。只要判断这俩个坐标合法就可以了,然后继续插入新的元素到deque,然后删除
deque前面不合法的元素……重复即可
为什么只要判断2个元素就OK了呢,
假如队尾元素是p0(x, 5).y小一点点的是p1(x, 4),大一点点的是p2(x, 6)
如果存在p3(x, y)也和p0合法
那么他一定已经和p1或者p2并到一个集合里去了……
因为显然p3和p1,p2的X坐标一定是合法的(X坐标从小到大排序了嘛,p3和p0合法,一定和p1,p2合法)
如果p3的y坐标一定大于p2.y 或者小于p1.y 那么他一定在处理p1或者p2(或者把p1,p2看成p0,再往前推)的时候并到一起了……
我太弱了,语言也表述不清了
(读入改为getchar直接就rank2了 >< rank1的pz手写了treap的样子好厉害)
#include <cstdio>#include <set>#include <deque>#include <algorithm>using namespace std;#define df pop_front()const int max_n = 100000 + 10;struct node{ int x, y, self; node(){} node(int X,int Y, int SELF): x(X + Y), y(X - Y), self(SELF){} inline bool operator < (const node &A) const { if (y == A.y) return x < A.x; return y < A.y; } }dot[max_n];set<node>::iterator it, sb;set<node>g;deque<node>q;int n, D;inline void read(int &x){ char ch; while (ch=getchar(),ch>'9' || ch<'0'); x=ch-48; while (ch=getchar(),ch<='9' && ch>='0') x=x*10+ch-48; } inline int cmp(node A, node B){ return A.x < B.x;} int fa[max_n] = {0};int have[max_n]; int find_father(int k){ if (!fa[k]) return k; fa[k] = find_father(fa[k]); have[k] = 0; return fa[k];} int main(){ int x, y; read(n); read(D); for (int i = 1; i <= n; ++ i) { read(x); read(y); dot[i] = node(x, y, i); } for (int i = 1; i <= n; ++ i) have[i] = 1; sort(dot + 1, dot + 1 + n, cmp); q.push_back(dot[1]); g.insert(dot[1]); for (int i = 2; i <= n; ++ i) { while (!q.empty() && dot[i].x - q[0].x > D) { g.erase(q[0]); q.df; } q.push_back(dot[i]); g.insert(dot[i]); it = g.find(dot[i]); ++ it; if (it != g.end() && (*it).y - dot[i].y <= D) { int a = find_father(dot[i].self); int b = find_father((*it).self); if (a != b) { int da = b, xiao = a; if (have[a] > have[b]) { da = a; xiao = b; } fa[xiao] = da; have[da] += have[xiao]; have[xiao] = 0; } } -- it; if (it != g.begin()) { -- it; if (dot[i].y - (*it).y > D) continue; int a = find_father(dot[i].self); int b = find_father((*it).self); if (a != b) { int da(b), xiao(a); if (have[a] > have[b]) { da = a; xiao = b; } fa[xiao] = da; have[da] += have[xiao]; have[xiao] = 0; } } } int tot = 0, ans = 0; for (int i = 1; i <= n; ++ i) { ans = max(ans, have[i]); if (have[i]) ++ tot; } printf("%d %d\n", tot, ans); return 0;}
getchar版,没什么区别啦~只不过当时想rank1结果失败了><:
#include <cstdio>#include <set>#include <deque>#include <algorithm>using namespace std;#define df pop_front() const int max_n = 100000 + 10; struct node{ int x, y, self; node(){} node(int X,int Y, int SELF): x(X + Y), y(X - Y), self(SELF){} inline bool operator < (const node &A) const { if (y == A.y) return x < A.x; return y < A.y; } }dot[max_n];set<node>::iterator it, sb;set<node>g;deque<node>q;int n, D; inline void read(int &x){ char ch; while (ch=getchar(),ch>'9' || ch<'0'); x=ch-48; while (ch=getchar(),ch<='9' && ch>='0') x=x*10+ch-48; } inline int cmp(node A, node B){ return A.x < B.x;} int fa[max_n] = {0};int have[max_n]; int find_father(int k){ if (!fa[k]) return k; fa[k] = find_father(fa[k]); have[k] = 0; return fa[k];} int main(){ int x, y; read(n); read(D); for (int i = 1; i <= n; ++ i) { read(x); read(y); dot[i] = node(x, y, i); } for (int i = 1; i <= n; ++ i) have[i] = 1; sort(dot + 1, dot + 1 + n, cmp); q.push_back(dot[1]); g.insert(dot[1]); for (int i = 2; i <= n; ++ i) { while (!q.empty() && dot[i].x - q[0].x > D) { g.erase(q[0]); q.df; } q.push_back(dot[i]); g.insert(dot[i]); it = g.find(dot[i]); ++ it; if (it != g.end() && (*it).y - dot[i].y <= D) { int a = find_father(dot[i].self); int b = find_father((*it).self); if (a != b) { int da = b, xiao = a; if (have[a] > have[b]) { da = a; xiao = b; } fa[xiao] = da; have[da] += have[xiao]; have[xiao] = 0; } } -- it; if (it != g.begin()) { -- it; if (dot[i].y - (*it).y > D) continue; int a = find_father(dot[i].self); int b = find_father((*it).self); if (a != b) { int da(b), xiao(a); if (have[a] > have[b]) { da = a; xiao = b; } fa[xiao] = da; have[da] += have[xiao]; have[xiao] = 0; } } } int tot = 0, ans = 0; for (int i = 1; i <= n; ++ i) { ans = max(ans, have[i]); if (have[i]) ++ tot; } printf("%d %d\n", tot, ans); return 0;}
- BZOJ 1604: [Usaco2008 Open]Cow Neighborhoods
- BZOJ 1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居
- BZOJ 1604 [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 Treap
- bzoj 1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居
- BZOJ 1604 [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居
- 并查集+Set-BZOJ-1604-[Usaco2008 Open]Cow Neighborhoods 奶牛的邻居
- 【bzoj 1604】: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 set+并查集
- bzoj 1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居(set+并查集)
- [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居
- bzoj 1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居(切比雪夫距离+multiset贪心+并查集)
- BZOJ 1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 曼哈顿距离转切比雪夫距离 Treap
- bzoj1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居
- 【bzoj1604】: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居
- [BZOJ1604] [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居
- 【bzoj1604】【[Usaco2008 Open]Cow Neighborhoods】简单的谈谈曼哈顿距离
- 【bzoj1604】【Usaco2008 Open】Cow Neighborhoods (set+曼哈顿距离性质+并查集)奶牛的邻居
- [BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的邻居(multiset+并查集)
- 【BZOJ 1604】Cow Neighborhoods(哈夫曼距离+Multiset)
- pl/sql游标
- 排序(二)——关于希尔排序
- Hi3521开发
- scrollTop与scrollLeft
- zzuli1619--发工资--用访问数组判断是否有环
- BZOJ 1604: [Usaco2008 Open]Cow Neighborhoods
- Scrapy-CrawlSpider爬虫组件
- LINUX下USB1.1设备学习小记(5)_uhci与设备(1)
- Objective-C中的枚举类型
- zoj1119--双连通--寻找关节点---计算子网数
- poj3352--旅游岛修路--双连通--无向图邻接表的容量是边数量的2倍
- 记录一次IllegalStateException异常的解决过程
- hbase基本概念和hbase shell常用命令用法
- poj1236--强连通--tarjan--补强连通--最优分发