• 线段树专辑——pku 2777 Count Color


    http://poj.org/problem?id=2777

    又是一个区间染色问题,和一般的区间染色问题有点点不同,在于这题的线段范围比较大,如果采用cover域表示法的话会超时。

    所谓cover域表示法,即当cover值为-1时,表示该线段的颜色为混合色,要求的具体答案必须向下查找,直到找到cover不为-1的子区间。

    但是cover表示法也不错,因为我们有时候会别无选择。下面会为大家进行比较。先看这题的题解!

    这题虽然线段范围很大,但是我们注意到所用到的颜色最多只有30中,如果采用二进制压缩法的话,一个int 型数据即可以表示出所有的颜色(例如:1001表示了两种颜色,第一种和第四种) 。为线段树添加一个color域,用于表示该线段上有哪些颜色,我们注意到颜色已经压缩成了二进制,那么某区间的颜色便等于它左右两子区间的 ‘或’操作值!采用lazy思想,标记哪些线段是单色的,是单色的,我们便往下传递,最后回溯,利用或操作跟新线段树,这样便大大的剩下了时间!

    View Code
      1 #include<iostream>
    2 #include<string>
    3 #include<algorithm>
    4 using namespace std;
    5
    6 struct node
    7 {
    8 int l;
    9 int r;
    10 int color;
    11 int lazy; //lazy为1表示为颜色需要向下传递
    12 };
    13
    14 node tree[500000];
    15 int n,t,m;
    16
    17 void build(int i,int l,int r)
    18 {
    19 tree[i].l=l;
    20 tree[i].r=r;
    21 tree[i].color=1; //题目初始颜色为1
    22 tree[i].lazy=0;
    23 if(l==r)
    24 return;
    25 int mid=(l+r)/2;
    26 build(2*i,l,mid);
    27 build(2*i+1,mid+1,r);
    28 }
    29
    30 void updata(int i,int l,int r,int w)
    31 {
    32 if(tree[i].l>r || tree[i].r<l)
    33 return;
    34 if(tree[i].l>=l && tree[i].r<=r)
    35 {
    36 tree[i].color=w; //完全覆盖,将新颜色覆盖旧颜色
    37 tree[i].lazy=1; //同时标记该线段为单色
    38 return;
    39 }
    40 if(tree[i].lazy) //该线段为单色,需要向下传递
    41 {
    42 tree[2*i].color=tree[2*i+1].color=tree[i].color;
    43 tree[2*i].lazy=tree[2*i+1].lazy=1;
    44 tree[i].lazy=0;
    45 }
    46 updata(2*i,l,r,w);
    47 updata(2*i+1,l,r,w);
    48 tree[i].color=tree[2*i].color|tree[2*i+1].color; //回缩跟新
    49 }
    50
    51 int ans;
    52 void find(int i,int l,int r)
    53 {
    54 if(tree[i].l>r || tree[i].r<l)
    55 return;
    56 if(tree[i].l>=l && tree[i].r<=r)
    57 {
    58 ans=ans|tree[i].color;
    59 return;
    60 }
    61 if(tree[i].lazy) //该线段为单色,需要向下传递
    62 {
    63 tree[2*i].color=tree[2*i+1].color=tree[i].color;
    64 tree[2*i].lazy=tree[2*i+1].lazy=1;
    65 tree[i].lazy=0;
    66 }
    67 find(2*i,l,r);
    68 find(2*i+1,l,r);
    69 }
    70
    71 void print(int x)
    72 {
    73 int ans=0;
    74 while(x)
    75 {
    76 x-=(x&(-x));
    77 ans++;
    78 }
    79 printf("%d\n",ans);
    80 }
    81
    82 int main()
    83 {
    84 int a,b,w,i;
    85 char c;
    86 freopen("in.txt","r",stdin);
    87 while(scanf("%d%d%d",&n,&t,&m)!=EOF)
    88 {
    89 build(1,1,n);
    90 for(i=0;i<m;i++)
    91 {
    92 getchar();
    93 scanf("%c",&c);
    94 if(c=='C')
    95 {
    96 scanf("%d%d%d",&a,&b,&w);
    97 if(a>b) //恶心的地方,Wa了好多次
    98 swap(a,b);
    99 updata(1,a,b,1<<(w-1)); //颜色压缩
    100 }
    101 else
    102 {
    103 scanf("%d%d",&a,&b);
    104 if(a>b)
    105 swap(a,b);
    106 ans=0;
    107 find(1,a,b);
    108 print(ans);
    109 }
    110 }
    111 }
    112 return 0;
    113 }

    这样,我们便顺利的A掉了这题。可是回头想想,这样的方法虽然快,可并不通用,因为二进制的压缩数目毕竟有限。如果题目涉及到了10000种颜色,那还怎么压缩?那就只能用cover域来标记了。不过那样的题目线段范围一定会合理的,不然还让人怎么活?~~

  • 相关阅读:
    单例模式
    java笔记 chapter7 抽象类和数组
    java笔记 chapter6 StringBuffer类和String Bulider类,Math类 Date类,Calendar类
    设计上的若干问题
    Java中的二次分发
    关于抽象
    SSI框架下同一个Bean加载了2次问题解决
    Hello 2015
    关于window.location.href is not a function在FF,chrom报错问题
    使用Eclipse的一些小心得!
  • 原文地址:https://www.cnblogs.com/ka200812/p/2243632.html
Copyright © 2020-2023  润新知