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;}