zoukankan      html  css  js  c++  java
  • [BZOJ1594] [Usaco2008 Jan]猜数游戏(二分 + 并查集)

    传送门

    题中重要信息,每堆草的数量都不一样。

    可以思考一下,什么情况下才会出现矛盾。

    1.如果两个区间的最小值一样,但是这两个区间没有交集,那么就出现矛盾。

    2.如果两个区间的最小值一样,并且这两个区间有交集,那么这个最小值一定在交集中,但是如果这个交集被某个最小值较大的区间,或是一些最小值较大的区间的并集包含,那么也是矛盾的。

    可以二分答案,将这些区间按照最小值从大到小排序,然后可以用线段树维护,也可以用并查集来搞。

    下面是用并查集来搞的。

    每到一个区间,可以将[l,r]中的f变成r+1,如果发现find(l) > r那么说明这个区间已经被最小值较大的区间所包含。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #define N 1000011
    #define min(x, y) ((x) < (y) ? (x) : (y))
    #define max(x, y) ((x) > (y) ? (x) : (y))
    
    int n, q, ans;
    int f[N];
    
    struct node
    {
    	int x, y, z;
    }p[N], t[N];
    
    inline int read()
    {
    	int x = 0, f = 1;
    	char ch = getchar();
    	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
    	for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
    	return x * f;
    }
    
    inline bool cmp(node x, node y)
    {
    	return x.z > y.z;
    }
    
    inline int find(int x)
    {
    	return x == f[x] ? x : f[x] = find(f[x]);
    }
    
    inline bool check(int k)
    {
    	int i, j, x, y, lmin, lmax, rmin, rmax;
    	for(i = 1; i <= n + 1; i++) f[i] = i;
    	for(i = 1; i <= k; i++) t[i] = p[i];
    	std::sort(t + 1, t + k + 1, cmp);
    	lmin = lmax = t[1].x;
    	rmin = rmax = t[1].y;
    	for(i = 2; i <= k; i++)
    	{
    		if(t[i].z < t[i - 1].z)
    		{
    			if(find(lmax) > rmin) return 1;
    			for(j = find(lmin); j <= rmax; j++)
    				f[find(j)] = find(rmax + 1);
    			lmin = lmax = t[i].x;
    			rmin = rmax = t[i].y;
    		}
    		else
    		{
    			lmin = min(lmin, t[i].x);
    			lmax = max(lmax, t[i].x);
    			rmin = min(rmin, t[i].y);
    			rmax = max(rmax, t[i].y);
    			if(lmax > rmin) return 1;
    		}
    	}
    	if(find(lmax) > rmin) return 1;
    	return 0;
    }
    
    int main()
    {
    	int i, x, y, mid;
    	n = read();
    	q = read();
    	for(i = 1; i <= q; i++)
    		p[i].x = read(), p[i].y = read(), p[i].z = read();
    	x = 1, y = q;
    	while(x <= y)
    	{
    		mid = (x + y) >> 1;
    		if(check(mid)) ans = mid, y = mid - 1;
    		else x = mid + 1;
    	}
    	printf("%d
    ", ans);
    	return 0;
    }
    

      

  • 相关阅读:
    采用[ICONIX] 方法实践BLOG设计之一 [问题域建模]
    关于“三国众谋士”之IT从业可行性报告
    采用[ICONIX] 方法实践BLOG设计之二 [用例建模]
    NET框架中的 Decorator 和 Strategy 模式
    域模型向左走(充血),向右走(贫血)
    采用[ICONIX] 方法实践BLOG设计之五 [初步设计复核]
    Discuz!NT 缓存设计简析 [原创]
    Discuz!NT控件剖析 之 Tab 属性页 [原创: 附源码]
    没有银弹,但可以"扯蛋"
    Discuz!NT控件剖析 之 Button [原创: 附源码]
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/7524445.html
Copyright © 2011-2022 走看看