• pku2777 线段树(染色问题)


      先来谈谈lazy思想。做了这么多的线段树,应该总结一下,lazy是一个很经典的思
    想。所谓lazy,就是懒惰,每次不想做太多,只要插入的区间完全覆盖了当前结点所管
    理的区间就不再往下做了,在当前结点上打上一个lazy标记,然后直接返回。下次如果
    遇到当前结点有lazy标记的话,直接传递给两个儿子,自己的标记清空。这样做肯定是
    正确的。我们以染色为例,可以这样想,如果当前结点和它的子孙都有lazy标记的话,
    必定是子孙的先标记,因为如果是自己先标记,那么在访问子孙的时候,必定会将自己
    的标记下传给儿子,而自己的标记必定会清空,那么lazy标记也就不存在了。所以可以
    肯定,当前的lazy标记必定覆盖了子孙的,所以直接下传即可,不需要做任何判断。当
    然,这是染色问题,是直接赋值的,如果像pku 3468那样,每次是区间加和,则传递标
    记的时候不能简单的赋值,必须累加,这是显而易见的。

     一看到数据量就可以首先确定是线段树了,经典的区间染色问题,涉及到区间的
    更新和询问,和pku 3468 类似,巧妙运用lazy思想。就是每次更新区间段的时候延迟
    更新,只是在完全覆盖的区间打上一个lazy标记。这题的询问是求区间段中不同颜色的
    数量,因为颜色数不多只有30种,可以巧妙运用二进制位运算,用一个int就可以表示
    当前区间段的颜色情况。比如1001表示有两种颜色,如果左子树的当前颜色情况是101
    ,而右子树的颜色情况是011,那么父亲的颜色情况就是两者的位或,这样就可以避免
    掉重复的情况。

    #include<stdio.h>
    #define N 100010
    struct node{
    int l,r,c;
    }p[N
    *3];
    int flag,count;
    void bulid(int k,int s,int t)
    {
    int kl,kr,mid;
    p[k].r
    =t;p[k].l=s;
    p[k].c
    =1;
    if(t==s)return ;

    mid
    =(s+t)>>1;kl=k<<1;kr=kl+1;
    bulid(kl,s,mid);
    bulid(kr,mid
    +1,t);

    }
    void updata(int k,int s,int t,int v)
    {
    int kr,kl,mid;
    if(p[k].c==v)
    return ;
    if(s<=p[k].l&&t>=p[k].r)
    p[k].c
    =v;
    else {
    mid
    =(p[k].r+p[k].l)>>1;kl=k<<1;kr=kl+1;
    if(p[k].c!=-1)
    {
    p[kr].c
    =p[kl].c=p[k].c;
    p[k].c
    =-1;
    }
    if(s<=mid)updata(kl,s,t,v);
    if(t>mid)updata(kr,s,t,v);
    }
    }
    void query(int k,int s,int t)
    {
    int kr,kl,mid;
    if(p[k].c>0)
    {
    int t=p[k].c;
    if((flag&(1<<t))==0)//由于颜色只有30种,所以可以用位运算来标记状态
    { //注意这里的移位操作,flag的32个位上的1和0分别表示该位的位置代表的
    // 颜色是否存在过,先将1左移t个位,则只有第t+1个位上的数字为1,其余为0,
    count
    ++; // 当与flag进行位与运算等于0时,则表示所对应的颜色没出现过
    flag
    |=1<<t; //同样的,若出现过,则用flag在该位上标记一下
    }
    return ;
    }
    mid
    =(p[k].r+p[k].l)>>1;kl=k<<1;kr=kl+1;
    if(s<=mid) query(kl,s,t);
    if(t>mid) query(kr,s,t);
    }
    int main()
    {
    int n,m,a,b,x,t;
    char ch[2];
    while(scanf("%d %d %d",&n,&t,&m)!=EOF)
    {
    bulid(
    1,1,n);
    while(m--)
    {
    scanf(
    "%s",ch);
    if(ch[0]=='C')
    {
    scanf(
    "%d %d %d",&a,&b,&x);
    if(a>b) { t=a;a=b;b=t;}
    updata(
    1,a,b,x);
    }
    else {
    flag
    =count=0;
    scanf(
    "%d %d",&a,&b);
    if(a>b){t=a;a=b;b=t;}
    query(
    1,a,b);
    printf(
    "%d\n",count);
    }
    }
    }
    return 0;
    }
  • 相关阅读:
    The user specified as a definer (”@’%') does not exist解决方法
    mongodb下载地址
    镜像系统,超好用
    部署mysql后,无法设置用户远程登陆(%只所有用户,不可以,只能给指定的ip?)
    Libcap的简介及安装
    GCC命令基础
    gcc安装(centos)
    React Native 踩坑
    webpack 和 babel
    React 开发笔记
  • 原文地址:https://www.cnblogs.com/nanke/p/2032206.html
Copyright © 2020-2023  润新知