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


    http://www.lydsy.com/JudgeOnline/problem.php?id=1604

    这题太神了。。。

    简直就是 神思想+神做法+神stl。。

    被stl整的我想cry。。。首先,,erase的时候如果没有这个元素。。。。。。那么。。。。。(TAT)否则你就要先find(重载<)然后要注意multiset,因为你重载的<运算只判<的话会将值相同(假如这是个结构,有多种元素,它只会判断你重载符号的运算满不满足,,而不去匹配其它项。。所以会错。。)的去掉。。。。。// upd:因为multiset一次删完了所有相同的东西囧QAQ

    并且为了避免re。。我们要插入2个边界元素(同时要注意算术溢出!!我wa了几次。。)

    说这题的做法:

    首先我们来分析|X-x|+|Y-y|,怎么看都感觉不对。。。。。。。。。。。。我们来变一下。。

    因为是绝对值,所以有四种情况,但是你拆完后会发现,会变成这样

    X-x+Y-y -> (X+Y)-(x+y)

    X-x+y-Y -> (X-Y)-(x-y)

    x-X+Y-y -> -( (X-Y)-(x-y) )

    x-X+y-Y -> -( (X+Y)-(x+y) )

    这四种情况,我们可以发现,答案就是

    max( |(X+Y)-(x+y)|, |(X-Y)-(x-y)| )

    那么我们可以对每个点处理成(X+Y, X-Y)的形式

    那么处理后怎么做呢?

    我们对这些新的点按新的x排序

    然后维护一个队列,里边对应的两两元素的x轴之差都<=c,即每次加入一个元素进来时,如果队列中最小的x值(即队头)与这个值的差>c,那么队头出队列。

    这样保证了这些队列中的元素在x轴范围内是符合条件的,即我们做了max两边元素的左边一个。

    那么怎么做右边的一个呢

    我们将当且所有可能的节点维护一种数据结构存y,其中保证y的差都在范围内(这里不同于上边的x,这里只是保证至少有一个y与另一个y之差小于c,即这些都在一个集合里边)

    那么怎么维护新加入进来的元素呢。

    很简单,因为之前的y都是满足这个条件的,所以我们只需要找一个比当前要加入的点的y小的(最大的那个)和一个比y大的(最小的那个),然后判断是否差在c里边

    如果满足,直接加入这个集合。

    正确性显然。

    而我们怎么维护答案集合呢,因为我们加入队列的方式是直接比较队头,则队列里的集合不一定是完整的集合(因为有可能满足的点已经出队了),那么我们就用并查集维护他们。。

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <set>
    using namespace std;
    #define rep(i, n) for(int i=0; i<(n); ++i)
    #define for1(i,a,n) for(int i=(a);i<=(n);++i)
    #define for2(i,a,n) for(int i=(a);i<(n);++i)
    #define for3(i,a,n) for(int i=(a);i>=(n);--i)
    #define for4(i,a,n) for(int i=(a);i>(n);--i)
    #define CC(i,a) memset(i,a,sizeof(i))
    #define read(a) a=getint()
    #define print(a) printf("%d", a)
    #define dbg(x) cout << #x << " = " << x << endl
    #define printarr(a, n, m) rep(aaa, n) { rep(bbb, m) cout << a[aaa][bbb]; cout << endl; }
    inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
    inline const int max(const int &a, const int &b) { return a>b?a:b; }
    inline const int min(const int &a, const int &b) { return a<b?a:b; }
    
    const int N=100005, oo=~0u>>1;
    int p[N], sum[N], front, c, n, ans, mx;
    struct dat { int x, y; }a[N];
    multiset<dat> s;
    set<dat>::iterator it;
    inline const bool operator< (const dat &a, const dat &b) { return a.x<b.x; }
    const int ifind(const int &x) { return x==p[x]?x:p[x]=ifind(p[x]); }
    inline void un(const int &x, const int &y) { int fx=ifind(x), fy=ifind(y); if(fx!=fy) p[fx]=fy, --ans; }
    
    int main() {
    	read(n); read(c);
    	int x, y; ans=n;
    	for1(i, 1, n) read(x), read(y), a[i].x=x+y, a[i].y=x-y, p[i]=i;
    	sort(a+1, a+1+n); front=1;
    	s.insert((dat){oo, 0}); s.insert((dat){-oo, 0});
    	for1(i, 1, n) {
    		while(a[i].x-a[front].x>c) {
    			s.erase(s.lower_bound((dat){a[front].y, front}));
    			++front;
    		}
    		long long y=a[i].y;
    		it=s.lower_bound((dat){a[i].y, i});
    		dat r=*it, l=*--it;
    		if((long long)r.x-y <= c) un(r.y, i);
    		if(y-(long long)l.x <= c) un(l.y, i);
    		s.insert((dat){a[i].y, i});
    	}
    	for1(i, 1, n) ++sum[ifind(i)];
    	for1(i, 1, n) mx=max(mx, sum[i]);
    	printf("%d %d", ans, mx);
    	return 0;
    }
    

    Description

    了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的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均同属一个群.
        给出奶牛们的位置,请计算草原上有多少个牛群,以及最大的牛群里有多少奶牛

    Input

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

    Output

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

    Sample Input

    4 2
    1 1
    3 3
    2 2
    10 10

    * Line 1: A single line with a two space-separated integers: the
    number of cow neighborhoods and the size of the largest cow
    neighborhood.



    Sample Output

    2 3

    OUTPUT DETAILS:
    There are 2 neighborhoods, one formed by the first three cows and
    the other being the last cow. The largest neighborhood therefore
    has size 3.

    HINT

    Source

  • 相关阅读:
    存储过程使用收集
    网站伪静态技术(网页伪静态化)
    鼠标拖动层
    Oracle系统中用户权限的赋予,查看和管理(3)
    数据库中的锁查询及相关关系
    undo 管理
    grant 和 REVOKE权限
    Oracle系统中用户权限的赋予,查看和管理(2)
    了解数据库不同启动
    Oracle系统中用户权限的赋予,查看和管理(注意点)(4)
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/3968835.html
Copyright © 2020-2023  润新知