[BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 (Treap+单调队列)
题面
了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的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均同属一个群.
给出奶牛们的位置,请计算草原上有多少个牛群,以及最大的牛群里有多少奶牛
分析
观察\(|x_i-x_j|+|y_i-y_j| \leq C\),发现这个式子和x,y都有关,不便维护
我们将点(x,y)变成(X,Y),其中X=x+y,Y=x-y,那么之后两点间的距离就可以写成\(max(|X_i-X_j|,|Y_i-Yj|)\)
设两点坐标为\((x_1,y_1),(x_2,y_2)\),变形之后就变成了\((x_1+y_1,x_1-y_1)(x_2+y_2,x_2-y_2)\),那么\(|X_i-X_j|=|(x_1-x_2)+(y_1-y_2)|,|Y_i-Yj|=|(x_1-x_2)+(y_2-y_1)|\)。讨论x,y的大小关系即可证明,这里不再赘述
经过上面的转化,我们现在只要保证\(max(|X_i-X_j|,|Y_i-Yj|) \leq C\),即\(|X_i-X_j| \leq C,|Y_i-Yj| \leq C\)
因此我们按X[i]从小到大把点排序,然后维护一个队列,满足\(X_{tail}-X_{head} \leq C\),否则就将head出队。那么Y的条件怎么满足呢。我们维护一棵平衡树存储当前队列里的所有点的Y坐标,然后对于新插入的\(Y_{tail}\),我们在平衡树里查找它的前驱和后继,判断它们的距离是否<=C,如果是,就将它们的编号合并(用一个并查集)
最后在并查集里查找即可
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define maxn 100005
#define INF 0x7fffffff
using namespace std;
int n,c;
struct point{
int x;
int y;
int id;
point(){
}
point(int xx,int yy,int i){
x=xx;
y=yy;
id=i;
}
friend bool operator < (point p,point q){
return p.x<q.x;
}
};
point a[maxn],q[maxn*2];
int head=0,tail=0;
struct value{
int v;
int id;
value(){
}
value(int y,int i){
v=y;
id=i;
}
friend bool operator < (value p,value q){
if(p.v==q.v) return p.id<q.id;
return p.v<q.v;
}
friend bool operator <= (value p,value q){
return p==q||p<q;
}
friend bool operator > (value p,value q){
if(p.v==q.v) return p.id>q.id;
return p.v>q.v;
}
friend bool operator >= (value p,value q){
return p>q||p==q;
}
friend bool operator == (value p,value q){
return p.id==q.id&&p.v==q.v;
}
};
struct treap{
struct node{
int ls;
int rs;
int cnt;
int sz;
value val;
int dat;
}tree[maxn];
int root;
int ptr;
int New(value val){
ptr++;
tree[ptr].ls=tree[ptr].rs=0;
tree[ptr].cnt=tree[ptr].sz=1;
tree[ptr].val=val;
tree[ptr].dat=rand();
return ptr;
}
void push_up(int x){
tree[x].sz=tree[tree[x].ls].sz+tree[tree[x].rs].sz+tree[x].cnt;
}
void rturn(int &x){
int y=tree[x].ls;
tree[x].ls=tree[y].rs;
tree[y].rs=x;
x=y;
push_up(tree[x].rs);
push_up(x);
}
void lturn(int &x){
int y=tree[x].rs;
tree[x].rs=tree[y].ls;
tree[y].ls=x;
x=y;
push_up(tree[x].ls);
push_up(x);
}
void insert(int &x,value val){
if(x==0){
x=New(val);
return;
}
if(tree[x].val==val){
tree[x].cnt++;
push_up(x);
return;
}
if(val<tree[x].val){
insert(tree[x].ls,val);
if(tree[tree[x].ls].dat>tree[x].dat){
rturn(x);
}
}else{
insert(tree[x].rs,val);
if(tree[tree[x].rs].dat>tree[x].dat){
lturn(x);
}
}
push_up(x);
}
value get_pre(int x,value val){
if(x==0) return value(-INF,0);
if(tree[x].val>val) return get_pre(tree[x].ls,val);
else return max(tree[x].val,get_pre(tree[x].rs,val));
}
value get_nex(int x,value val){
if(x==0) return value(INF,0);
if(tree[x].val<val) return get_nex(tree[x].rs,val);
else return min(tree[x].val,get_nex(tree[x].ls,val));
}
void del(int &x,value val){
if(x==0) return;
if(tree[x].val==val){
if(tree[x].cnt>1){
tree[x].cnt--;
push_up(x);
return;
}else{
if(tree[x].ls||tree[x].rs){
if(tree[x].rs==0||tree[tree[x].ls].dat>tree[tree[x].rs].dat){
rturn(x);
del(tree[x].rs,val);
}
else{
lturn(x);
del(tree[x].ls,val);
}
push_up(x);
}else x=0;
return;
}
}
if(val<tree[x].val) del(tree[x].ls,val);
else del(tree[x].rs,val);
push_up(x);
}
}T;
struct DSU{
int fa[maxn];
int cnt[maxn];
void ini(int n){
for(int i=1;i<=n;i++) fa[i]=i;
}
int find(int x){
if(fa[x]==x) return x;
else return fa[x]=find(fa[x]);
}
void merge(int x,int y){
int fx=find(x);
int fy=find(y);
if(fx==fy) return;
fa[find(x)]=find(y);
tot--;
}
}S;
int main(){
// freopen("2.in","r",stdin);
int x,y;
scanf("%d %d",&n,&c);
for(int i=1;i<=n;i++){
scanf("%d %d",&x,&y);
a[i].x=x+y;
a[i].y=x-y;
a[i].id=i;
}
sort(a+1,a+1+n);
S.ini(n);
for(int i=1;i<=n;i++){
while(head<tail&&a[i].x-q[head].x>c){
T.del(T.root,value(q[head].y,q[head].id));
head++;
}
value pre=T.get_pre(T.root,value(a[i].y,a[i].id));
value nex=T.get_nex(T.root,value(a[i].y,a[i].id));
if(pre.v!=-INF&&a[i].y-pre.v<=c) S.merge(a[i].id,pre.id);
if(nex.v!=INF&&nex.v-a[i].y<=c) S.merge(a[i].id,nex.id);
q[tail++]=a[i];
T.insert(T.root,value(a[i].y,a[i].id));
}
for(int i=1;i<=n;i++){
int f=S.find(i);
S.cnt[f]++;
}
int ans=0,tot=0;
for(int i=1;i<=n;i++){
ans=max(ans,S.cnt[i]);
}
sort(S.fa+1,S.fa+1+n);
tot=unique(S.fa+1,S.fa+1+n)-S.fa-1;
printf("%d %d\n",tot,ans);
}
[BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 (Treap+单调队列)的更多相关文章
- [BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的邻居
[BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 试题描述 了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发 ...
- 【BZOJ1604】[Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 Treap+并查集
[BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 Description 了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000) ...
- [BZOJ1604] [Usaco2008 Open] Cow Neighborhoods 奶牛的邻居 (queue & set)
Description 了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发现她们已经结成了几个“群”.每只奶牛在吃草的时候有一个独一无二的位置坐标Xi,Yi(l ...
- [BZOJ1604] [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居(好题)
传送门 良心题解 #include <set> #include <cstdio> #include <iostream> #include <algorit ...
- BZOJ 1604 [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 Treap
题意:链接 方法: Treap 解析: 前几道资格赛的题水的不行,这道Gold的题就够分量辣. 首先这个曼哈顿距离啥的肯定能做文章,怎么转化是个问题,自己玩了一会没玩出来,就查了查曼哈顿距离的转化,发 ...
- BZOJ 1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居
题目 1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 Time Limit: 5 Sec Memory Limit: 64 MB Description ...
- bzoj 1604 [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居(set+并查集)
Description 了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发现她们已经结成了几个“群”.每只奶牛在吃草的 时候有一个独一无二的位置坐标Xi,Yi( ...
- 【BZOJ】1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居(set+并查集+特殊的技巧)
http://www.lydsy.com/JudgeOnline/problem.php?id=1604 这题太神了... 简直就是 神思想+神做法+神stl.. 被stl整的我想cry...首先,, ...
- bzoj 1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居——排序+贪心+set
Description 了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发现她们已经结成了几个“群”.每只奶牛在吃草的时候有一个独一无二的位置坐标Xi,Yi(l ...
随机推荐
- MiniUI学习笔记1-新手必读
1.mini的全局方法 2.Ajax jQuery 拥有完整的 Ajax 兼容套件.其中的函数和方法允许我们在不刷新浏览器的情况下从服务器加载数据. 详细jQuery Ajax教程,可参考这里. 3. ...
- utf8 中文
#include <iostream> #include <codecvt> #include <fstream> #include <string> ...
- Linux 部署或升级openssh7.5p1
运维Linux系统,部署或升级openssh是经常面临的事,以下已redhat6和redhat7为例. 在redhat6中部署openssh会有什么坑,在编辑openssh源码包时会报一些类似的错误, ...
- hdu 4717: The Moving Points 【三分】
题目链接 第一次写三分 三分的基本模板 int SanFen(int l,int r) //找凸点 { ) { //mid为中点,midmid为四等分点 ; ; if( f(mid) > f(m ...
- http各个状态码的含义
http各个状态码的含义:由三位数字组成,第一位定义了状态码的类型 常见状态码及解决方法 404:找不到,地址错误 500:逻辑错误 400:一般是入参不匹配 504:超时 2开头:(请求成功)表示成 ...
- linux运维、架构之路-Nginx提高
一.虚拟主机搭建 1.基于域名的虚拟主机 [root@web01 html]# cat nginx.conf worker_processes ; events { worker_connection ...
- CF613D Kingdom and its Cities 虚树 + 树形DP
Code: #include<bits/stdc++.h> #define ll long long #define maxn 300003 #define RG register usi ...
- 十二 windows临界区,其他各种mutex
一.windows临界区 类似于互斥量 == 临界区. 二.多次进入临界区 进入临界区(加锁): 离开临界区(解锁): 同一个线程中windows中相同临界区变量代表的临界区进入(entercirti ...
- win server2008关闭危险端口445,135,137,138,139的方法
在Windows server 2008系统上,有两种途经可以禁用本地端口: 1.通过Windows防火墙(比较简单,设置方便) 2.通过IP安全策略(比较复杂,功能强大,不依赖防火墙) 一.通过Wi ...
- [CSP-S模拟测试]:回文(hash+二维前缀和)
题目描述 闲着无聊的$YGH$秒掉上面两道题之后,开始思考有趣的回文串问题了. 他面前就有一个漂浮着的字符串.显然$YGH$是会$manacher$的,于是他随手求出了这个字符串的回文子串个数.但是他 ...