POJ 2777 Count Color (线段树成段更新+二进制思维)

题目链接:http://poj.org/problem?id=2777

题意是有L个单位长的画板,T种颜色,O个操作。画板初始化为颜色1。操作C讲l到r单位之间的颜色变为c,操作P查询l到r单位之间的颜色有几种。

很明显的线段树成段更新,但是查询却不好弄。经过提醒,发现颜色的种类最多不超过30种,所以我们用二进制的思维解决这个问题,颜色1可以用二进制的1表示,同理,颜色2用二进制的10表示,3用100,...。假设有一个区间有颜色2和颜色3,那么区间的值为二进制的110(十进制为6)。那我们就把一个区间的颜色种类表示为(左孩子的值‘|’右孩子的值)。

然后就是一个线段树的成段更新。

有个坑点是这个题目的l可能比r大...

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 using namespace std;
  5 const int MAXN = 275000;
  6 struct segtree {
  7     int l , r , val , lazy;
  8 }T[MAXN << 3];
  9 //获取颜色的种类
 10 int get(int n) {
 11     int cont = 0;
 12     while(n) {
 13         if(n & 1)
 14             cont++;
 15         n >>= 1;
 16     }
 17     return cont;
 18 }
 19
 20 void init(int p , int l , int r) {
 21     int mid = (l + r) >> 1;
 22     T[p].l = l , T[p].r = r , T[p].lazy = 0;
 23     if(l == r) {
 24         T[p].val = 1;
 25         return ;
 26     }
 27     init(p << 1 , l , mid);
 28     init((p << 1)|1 , mid + 1 , r);
 29     T[p].val = (T[p << 1].val | T[(p << 1)|1].val);
 30 }
 31
 32 void updata(int p , int l , int r , int val) {
 33     int mid = (T[p].l + T[p].r) >> 1;
 34     if(l == T[p].l && T[p].r == r) {
 35         T[p].val = val;
 36         T[p].lazy = val;
 37         return ;
 38     }
 39     if(T[p].lazy) {
 40         T[p << 1].val = T[(p << 1)|1].val = T[p].lazy;
 41         T[p << 1].lazy = T[(p << 1)|1].lazy = T[p].lazy;
 42         T[p].lazy = 0;
 43     }
 44     if(r <= mid) {
 45         updata(p << 1 , l , r , val);
 46     }
 47     else if(l > mid) {
 48         updata((p << 1)|1 , l , r , val);
 49     }
 50     else {
 51         updata(p << 1 , l , mid , val);
 52         updata((p << 1)|1 , mid + 1 , r , val);
 53     }
 54     T[p].val = (T[p << 1].val | T[(p << 1)|1].val);
 55 }
 56 //返回颜色种类的二进制对应的十进制的值
 57 int query(int p , int l , int r) {
 58     int mid = (T[p].l + T[p].r) >> 1;
 59     if(T[p].l == l && T[p].r == r) {
 60         return T[p].val;
 61     }
 62     if(T[p].lazy) {
 63         T[p << 1].val = T[(p << 1)|1].val = T[p].lazy;
 64         T[p << 1].lazy = T[(p << 1)|1].lazy = T[p].lazy;
 65         T[p].lazy = 0;
 66     }
 67     if(r <= mid) {
 68         return query(p << 1 , l , r);
 69     }
 70     else if(l > mid) {
 71         return query((p << 1)|1 , l , r);
 72     }
 73     else {
 74         return query(p << 1 , l , mid) | query((p << 1)|1 , mid + 1 , r);
 75     }
 76 }
 77
 78 int main()
 79 {
 80     int L , t , n , l , r , c;
 81     char str[5];
 82     while(~scanf("%d %d %d" , &L , &t , &n)) {
 83         init(1 , 1 , L);
 84         while(n--) {
 85             scanf("%s" , str);
 86             if(str[0] == ‘C‘) {
 87                 scanf("%d %d %d" , &l , &r , &c);
 88                 int temp = l + r;
 89                 l = min(l , r);
 90                 r = temp - l;
 91                 updata(1 , l , r , (1 << (c - 1)));
 92             }
 93             else {
 94                 scanf("%d %d" , &l , &r);
 95                 int temp = l + r;
 96                 l = min(l , r);
 97                 r = temp - l;
 98                 int res = get(query(1 , l , r));
 99                 printf("%d\n" , res);
100             }
101         }
102     }
103 }
时间: 2024-10-01 17:51:24

POJ 2777 Count Color (线段树成段更新+二进制思维)的相关文章

POJ训练计划2777_Count Color(线段树/成段更新/区间染色)

解题报告 题意: 对线段染色,询问线段区间的颜色种数. 思路: 本来直接在线段树上染色,lz标记颜色.每次查询的话访问线段树,求出颜色种数.结果超时了,最坏的情况下,染色可以染到叶子节点. 换成存下区间的颜色种数,这样每次查询就不用找到叶子节点了,用按位或来处理颜色种数. #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace

POJ 2777 Count Color (线段树+位运算)

题意很简单了,对一个区间有两种操作: 1. "C A B C" Color the board from segment A to segment B with color C. //A~B涂上颜色C 2. "P A B" Output the number of different colors painted between segment A and segment B (including). //输出A~B间颜色的种类数 题目链接:http://poj.o

POJ 2777 Count Color(线段树)

题目地址:POJ 2777 我去..延迟标记写错了.标记到了叶子节点上....这根本就没延迟嘛...怪不得一直TLE... 这题就是利用二进制来标记颜色的种类.然后利用或|这个符号来统计每个区间不同颜色种数. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h

Codeforces Round #149 (Div. 2) E. XOR on Segment (线段树成段更新+二进制)

题目链接:http://codeforces.com/problemset/problem/242/E 给你n个数,m个操作,操作1是查询l到r之间的和,操作2是将l到r之间的每个数xor与x. 这题是线段树成段更新,但是不能直接更新,不然只能一个数一个数更新.这样只能把每个数存到一个数组中,长度大概是20吧,然后模拟二进制的位操作.仔细一点就行了. 1 #include <iostream> 2 #include <cstdio> 3 #include <cmath>

poj 2777 count color 线段树

Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. There is a very long board with length L centimeter, L is a positive integer, so we can evenly d

poj 2777 Count Color(线段树、状态压缩、位运算)

Count Color Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 38921   Accepted: 11696 Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem.

POJ 2777 count color(线段树,lazy标记)

这里有一个思想:我们在更新的时候不必要更新到叶子节点,只要更新到当前区间包含线段树区间即可. 设计一个标志位,更新到此. A Simple Problem with Integers 也是一个类似的题目 设计两个函数 push_down 将结点信息传递到下层节点(inc, sub,) push_up      将下层节点信息反馈到上层(max,min,count) #include <map> #include <set> #include <queue> #inclu

POJ 2528 Mayor&#39;s posters (hash+线段树成段更新)

题意:有一面墙,被等分为1QW份,一份的宽度为一个单位宽度.现在往墙上贴N张海报,每张海报的宽度是任意的,但是必定是单位宽度的整数倍,且<=1QW.后贴的海报若与先贴的海报有交集,后贴的海报必定会全部或局部覆盖先贴的海报.现在给出每张海报所贴的位置(左端位置和右端位置),问张贴完N张海报后,还能看见多少张海报?(PS:看见一部分也算看到.) 思路:简单的成段更新,但是数据量是1千万,会MT,所以要区间压缩(离散化),保证覆盖的关系不变,离散化的时候有个易错的细节,poj数据水了,这个易错点引用h

poj 3468 A Simple Problem with Integers (线段树成段更新)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 77486   Accepted: 23862 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of