• bzoj1594[Usaco2008 Jan]Haybale Guessing猜数游戏


    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1594

    题目大意:

    N个数排成一列,有q个询问。每个询问告诉你区间[l,r]的最小值是多少(这N个数各不相同)。问你这q个询问有没有矛盾,有的话从哪里开始有矛盾。

    题解:

    二分+线段树

    有人用神奇姿势の并查集来代替线段树来搞..但是我不懂QwQ

    于是我就打了线段树。。代码迷の长&迷の慢。。orzorz

    我们要先想矛盾之处会在哪里。

    1、没有交集的两个区间出现了相同的最小值x。因为每个数各不相同。即x的交集不合法或者说没有交集。

    2、已知某段区间的最小值为x,但是这段区间中的某个子区间的最小值为y,而y<x,那么对于已知的条件就矛盾了。即x所在区间的并集包含了y所在区间的交集的话就矛盾了(x>y)

    二分答案,把询问排序。

    怎么排?按值从大到小,这样就方便处理矛盾2。

    把x的区间都找到,得到其交集和并集的区间。

    直接用交集的区间判断矛盾1咯。

    对于矛盾二,用线段树维护标记下在哪段区间(用并集标记)已经知道最小值。

    因为从大到小排的序,所以更新在线段树里标记的都是比现在的数大的数标记的。那么如果查询到现在这个数的交集区间已经被标记了,就是矛盾2啊有矛盾了。

    然后,,,就这样啊。。。

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define maxn 2000010
    #define Q 30000
    
    struct node {int l,r,c;}a[Q],b[Q];
    bool cmp(node x,node y){return x.c>y.c;}
    struct tree
    {
    	int l,r,lc,rc;bool c;
    }tr[maxn];int len,n;
    void bt(int l,int r)
    {
    	len++;int now=len;
    	tr[now].l=l;tr[now].r=r;
    	tr[now].lc=tr[now].rc=-1;
    	tr[now].c=0;
    	if (l<r)
    	{
    		int mid=(l+r)>>1;
    		tr[now].lc=len+1;bt(l,mid);
    		tr[now].rc=len+1;bt(mid+1,r);
    	}
    }
    void change(int now,int l,int r)
    {
    	if (tr[now].l==l && tr[now].r==r) {tr[now].c=1;return;}
    	int mid=(tr[now].l+tr[now].r)>>1,lc=tr[now].lc,rc=tr[now].rc;
    	if (r<=mid) change(lc,l,r);
    	else if (l>mid) change(rc,l,r);
    	else change(lc,l,mid),change(rc,mid+1,r);
    	if (!tr[now].c) tr[now].c=(tr[lc].c&tr[rc].c);
    }
    bool query(int now,int l,int r)
    {
    	if (tr[now].c) return true;
    	if (tr[now].l==l && tr[now].r==r) return tr[now].c;
    	int mid=(tr[now].l+tr[now].r)>>1,lc=tr[now].lc,rc=tr[now].rc;
    	if (r<=mid) return query(lc,l,r);
    	else if (l>mid) return query(rc,l,r);
    	else return (query(lc,l,mid)&query(rc,mid+1,r));
    }
    int mymin(int x,int y) {return (x<y)?x:y;}
    int mymax(int x,int y) {return (x>y)?x:y;}
    bool check(int mid)
    {
    	int i,j,k,l1,l2,r1,r2;
    	for (i=1;i<=n*2;i++) tr[i].c=0;
    	for (i=1;i<=mid;i++) b[i]=a[i];
    	sort(b+1,b+1+mid,cmp);
    	for (i=1;i<=mid;)
    	{
    		for (j=i;j<=mid && b[j].c==b[i].c;j++);
    		l1=l2=b[i].l;r1=r2=b[i].r;//[l1,r1]是交集区间 [l2,r2]是并集区间
    		for (k=i+1;k<j;k++)
    		{
    			l1=mymin(l1,b[k].l);
    			l2=mymax(l2,b[k].l);
    			r1=mymax(r1,b[k].r);
    			r2=mymin(r2,b[k].r);
    		}
    		if (l2>r2) return true;
    		if (query(1,l2,r2)) return true;
    		change(1,l1,r1);i=j;
    	}return false;
    }
    int main()
    {
    	//freopen("bales.in","r",stdin);
    	//freopen("bales.out","w",stdout);
    	int q,i,l,r,bk;
    	scanf("%d%d",&n,&q);
    	len=0;bt(1,n);
    	for (i=1;i<=q;i++)
    		scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].c);
    	l=1;r=q;bk=0;
    	while (l<=r)//二分
    	{
    		int mid=(l+r)>>1;
    		if (check(mid)) {bk=mid;r=mid-1;}
    		else l=mid+1;
    	}
    	printf("%d
    ",bk);
    	return 0;
    }


  • 相关阅读:
    Vue.js学习笔记 第五篇 事件处理
    多sheet导出核心代码
    jeecg查询备份
    输入URL 一瞬间发生了什么
    get post 的区别
    Redis所需内存 超过可用内存怎么办
    MySQL联合索引
    常用的sql
    MySQL 时间类型字段的分析
    PHP各个版本的区别
  • 原文地址:https://www.cnblogs.com/Euryale-Rose/p/6527834.html
Copyright © 2020-2023  润新知