洛谷P2898haybale猜测Haybale Guessing

来源:互联网 发布:邮箱绑域名有什么用 编辑:程序博客网 时间:2024/06/06 14:11

https://www.luogu.org/problemnew/show/2898

思路
显然,若按照题目给定的顺序处理,判断过程将异常麻烦….
但仔细分析题目后发现,本题对矛盾的产生有着诸多限制在。
那么我们可以考虑,对于矛盾的情况下一个统一定义
对于本题,则为“若某一确定了最小值的区间,被一个或多个最小值比他大的区间完全覆盖,那么此时的情况就是矛盾的。”—— 注意适当的将此种方法扩展到其他题目,使给定信息变得规律而易于处理。
由此我们就可以二分产生矛盾的第一个位置,将该位置及以前的猜测条件按猜测最小值从大到小排序后依次判断验证——因为顺序并不会影响矛盾的产生。

如何判断呢?

方法一:并查集

用类似数轴染色的方法进行区间染色,具体参考:
http://blog.csdn.net/qq_36693533/article/details/78428668
然后就是部分十分关键的细节处理问题:

1.我们设置lmax,lmin,rmax,rmin记录两个颜色(最小值)相同的区间中,较大,较小的左端点和较大,较小的右端点。则lmax-rmin为区间的交集(颜色确定),lmin-rmax为区间的并集(颜色未确定但其中不可完全包含之后最小值更小的区间)。,这两个范围对矛盾的产生都有影响所以都需要染色
另外,我们是通过交集范围是否在之前被染过色判断是否合法(1),和通过后面的区间是否被并集完全包含判断是否合法的(2)。请仔细想一下。

2.因为题目保证没有相同的数字,那么两个颜色相同的区间必定要存在交集,否则不合法。


3.对颜色相同的区间,我们只会更新其并集和交集范围,而要等到颜色相同的区间全部读完了,即等到我们读到一个颜色不同的区间为止,我们才会去验证之前颜色相同区间确定的并集范围有没有被更更早的区间染过色,这样一定是不合法的(矛盾定义)。(1),若合法则进行区间染色。

4.当我们读入一个与之前颜色不同区间后,我们并不知道其后是否有与之颜色相同的区间。方便起见,我们将lmax,lmin设为区间左端点,rmax,rmin设为区间右端点。
这样若之后的区间与之颜色相同,那么lmax,lmin,rmax,rmin都会被更新无影响。
若之后的区间与之颜色不同,那么我们对于交集的判断语句其实就成了判断前一个区间范围有没有被更更早的区间染过色,即判断当前区间有没有被之前(显然最小值较大)的区间完全包含。 (2)
关于不同的情况,需要注意的是,我们的判断是:如果区间范围完全被染过色才为非法,即我们之前读入的区间信息相对于当前信息为非法。

代码

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;int n,t,ans,lz,rz;int lmin,lmax,rmin,rmax;int fa[1000010];struct inte{    int ls,rs,mins;}p[1000010];inte tmp[1000010];bool cmp(inte a,inte b){    return a.mins>b.mins;}int find(int x){    return fa[x]==x?x:fa[x]=find(fa[x]);}int check(int k){    for(int i=1;i<=n+1;i++)//验证前k次判断对整个1-n区间的影响     fa[i]=i;               //数轴染色并查集的思路,若某一染色区间右端点为n,则将区间所以元素连至n+1下     for(int i=1;i<=k;i++)    tmp[i]=p[i];    sort(tmp+1,tmp+k+1,cmp);//从大到小排序    lmax=lmin=tmp[1].ls;    rmax=rmin=tmp[1].rs;     for(int i=2;i<=k;i++)    {        if(tmp[i].mins==tmp[i-1].mins)        {            lmin=min(lmin,tmp[i].ls);//更新             lmax=max(lmax,tmp[i].ls);            rmin=min(rmin,tmp[i].rs);            rmax=max(rmax,tmp[i].rs);            if(lmax>rmin) return 1;//若最小值相同的区域没有交集         }        else        {            if(find(lmax)>rmin)//当前区间已经被染过色,即当前最小值较小区间被最小值较大的区间完全覆盖             return 1;          //或之前的相同颜色区间的交集被染过色             for(int j=find(lmin);j<=rmax;j++)//与数轴染色不同,同一位置可能被多次染不同的颜色             {                                //用区间交集判断是否矛盾,但需将区间并集染色                 fa[find(j)]=find(rmax+1);            }            lmin=lmax=tmp[i].ls;//方便处理             rmin=rmax=tmp[i].rs;        }    }    if(find(lmax)>rmin)    return 1;//判断最后一次     return 0;}int main(){    scanf("%d%d",&n,&t);    for(int i=1;i<=t;i++)    scanf("%d%d%d",&p[i].ls,&p[i].rs,&p[i].mins);    lz=1;    rz=t;    ans=0;//一直没出现矛盾输出0     while(lz<=rz)//根据具体题目调整二分细节     {        int mid=(lz+rz)>>1;        if(check(mid))//若mid及mid之前存在矛盾,则已知当前的最小答案为mid,记录然后尝试缩小答案         {            ans=mid;            rz=mid-1;        }        else lz=mid+1;    }    printf("%d",ans);    return 0; }

方法二:线段树

思路参考并查集讲解,只是将并查集的区间染色换为了线段树的区间染色。
注意在本题中我们只维护区间是否被染过色即可。

代码

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>using namespace std;int n,t,ans,lz,rz;int lmin,lmax,rmin,rmax;struct inte{    int ls,rs,mins;}p[1000010];struct inie{    int l,r;}tree[4000010];int sum[4000010],add[4000010];//区间染色个数,标记,开与tree一样的空间 inte tmp[1000010];bool cmp(inte a,inte b){    return a.mins>b.mins;}void pushdown(int now){    if(add[now])    {        sum[now<<1]=(tree[now<<1].r-tree[now<<1].l+1);        sum[now<<1|1]=(tree[now<<1|1].r-tree[now<<1|1].l+1);        add[now<<1]=1;        add[now<<1|1]=1;        add[now]=0;    }}void update(int now){    sum[now]=sum[now<<1]+sum[now<<1|1]; }void build(int now,int l,int r){    tree[now].l=l;    tree[now].r=r;    if(l==r)    return;    int mid=(l+r)>>1;    build(now<<1,l,mid);    build(now<<1|1,mid+1,r);}void change(int now,int l,int r){    if(sum[now]==(tree[now].r-tree[now].l+1))//染过色的区间无需再染,减少递归次数     return;     if(tree[now].l>=l&&tree[now].r<=r)    {        sum[now]=tree[now].r-tree[now].l+1;        add[now]=1;        return;    }    pushdown(now);    int mid=(tree[now].l+tree[now].r)>>1;    if(l<=mid)    change(now<<1,l,r);    if(r>mid)    change(now<<1|1,l,r);    update(now);}int ask(int now,int l,int r){    if(tree[now].l>=l&&tree[now].r<=r)    return sum[now];    pushdown(now);    int ans=0;    int mid=(tree[now].l+tree[now].r)>>1;    if(l<=mid)    ans+=ask(now<<1,l,r);    if(r>mid)    ans+=ask(now<<1|1,l,r);    return ans; }int check(int k){    memset(sum,0,sizeof(sum));    memset(add,0,sizeof(add));    for(int i=1;i<=k;i++)    tmp[i]=p[i];    sort(tmp+1,tmp+k+1,cmp);    lmax=lmin=tmp[1].ls;    rmax=rmin=tmp[1].rs;     for(int i=2;i<=k;i++)    {        if(tmp[i].mins==tmp[i-1].mins)        {            lmax=max(lmax,tmp[i].ls);            lmin=min(lmin,tmp[i].ls);            rmax=max(rmax,tmp[i].rs);            rmin=min(rmin,tmp[i].rs);            if(lmax>rmin)            return 1;        }        else        {            if(ask(1,lmax,rmin)>=(rmin-lmax+1))            return 1;             change(1,lmin,rmax);            lmax=lmin=tmp[i].ls;            rmax=rmin=tmp[i].rs;        }    }    if(ask(1,lmax,rmin)>=(rmin-lmax+1))    return 1;    return 0;}int main(){    scanf("%d%d",&n,&t);    for(int i=1;i<=t;i++)    scanf("%d%d%d",&p[i].ls,&p[i].rs,&p[i].mins);    build(1,1,n);    lz=1;    rz=t;    ans=0;    while(lz<=rz)    {        int mid=(lz+rz)>>1;        if(check(mid))        {            ans=mid;            rz=mid-1;        }        else lz=mid+1;    }    printf("%d",ans);    return 0; }
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 我收到了方正的提示函怎么办 淘宝刷q币单被骗了怎么办 中通快递已签收但是东西丢了怎么办 手机不版本低不支持微信下载怎么办 淘宝虚拟商品不支持7天退货怎么办 卖虚拟物品遇到恶意退款买家怎么办 淘宝极速退款后卖家拒绝退款怎么办 我的天猫积分不让换券了怎么办 微信手机话费充错了怎么办 自己进货在淘宝卖被投诉假货怎么办 京东买的电器售后后服务差怎么办 京东到家申请退款卖家不处理怎么办 天猫买了假货商品下架了怎么办 淘宝本地生活服务不能入驻了怎么办 淘宝店铺名在电脑上搜索不到怎么办 已经将退货寄回店家硬说没有怎么办 微信申诉账号短信验证失败怎么办 京东账号换手机号收不到短信怎么办 我的手机收不到短信通知怎么办? 淘宝卖家发货物流单号写错了怎么办 商铺买东西不给调换大小怎么办 圆通快递物流信息一直没更新怎么办 中通快递三天没更新物流信息怎么办 快递已经到了物流信息不更新怎么办 天天快递查询不更新物流信息怎么办 买车下个月分期全部付清怎么办手续 天猫客服介入以后商家不退款怎么办 淘宝上买代购奢侈品买到假货怎么办 淘宝退货卖家收到货拒绝退款怎么办 没收到货但申请了退货退款怎么办 小米商城预约中德手机没货怎么办 电脑用百度网盘下载速度超慢怎么办 ios网盘下载速度太慢怎么办 小米手机4x卡机了怎么办 小米手机4x屏幕点不动了怎么办 苹果手机连接u盘没反应怎么办 苹果官网储蓄卡分期额度不够怎么办 京东买东西发票信息填写错了怎么办 华为v9手机激活密码忘了怎么办 公司报销发票纸质的丢了怎么办 在京东上买的小天才手表坏了怎么办