Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 42472   Accepted: 12850

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 divide the board into L segments, and they are labeled by 1, 2, ... L from left to right, each is 1 centimeter long. Now we have to color the board - one segment with only one color. We can do following two operations on the board:

1. "C A B C" Color the board from segment A to segment B with color C.
2. "P A B" Output the number of different colors painted between segment A and segment B (including).

In our daily life, we have very few words to describe a color (red, green, blue, yellow…), so you may assume that the total number of different colors T is very small. To make it simple, we express the names of colors as color 1, color 2, ... color T. At the beginning, the board was painted in color 1. Now the rest of problem is left to your.

Input

First line of input contains L (1 <= L <= 100000), T (1 <= T <= 30) and O (1 <= O <= 100000). Here O denotes the number of operations. Following O lines, each contains "C A B C" or "P A B" (here A, B, C are integers, and A may be larger than B) as an operation defined previously.

Output

Ouput results of the output operation in order, each line contains a number.

Sample Input

C
P
C
P

Sample Output


Source


  讲讲题目大意(反正很多单词我也不懂)

  有一个板子长L厘米,以1cm为单位进行涂色,一共有T种颜色,木板初始的颜色是

编号为1的颜色(颜色编号从1标到T),有o个操作,操作分两种

1. "C A B C"  将[a,b]涂成颜色C(涂色是覆盖)
2. "P A B" 输出[a,b]不同的颜色

  初看这道题觉得可能是用线段树做,于是想出了如下几个问题

    1.每个区间存储什么?

    2.pushUppushDown怎么更新

  第一问比较好解决,就存颜色的信息,如果说存颜色的种数(查完就完了),有一

个很严重的问题,两个区间的颜色可能会有重复,更新的时候还要去判重,显得十分地

麻烦,干脆直接存各种颜色的是否在这个区间存在

  这样就好了,定个bool数组,更新的时候就合并,另外又出现了一个无法避免的问题——

超内存、超时(时间限制是1s!),bool类型是1字节,等于8二进制位,是不是有点过于浪费

内存。那就把它分割一下,分成4个bool类型,这样,究竟用哪一个呢?这样貌似又要浪费代码。

反正T也不大,也就30,于是我想到了int...

  就这样第一问就解决了,那怎么更新呢?总不可能相加,位运算中有一个运算是|(或运算)

这样用起来快,也方便,比如有两个区间它们的涂色情况如下:

//假设有4种颜色
[,]
[,]

  通过or运算后:

[,]    

  都不用考虑重复的问题了

  pushUp就用这个来,将左右子树上的颜色信息相or就得到了父节点的颜色信息

  结合则来考虑一下pushDown ,查询区间的时候,应该是把节点上的区间完全

覆盖的情况下才会更改延时更新,所以这个区间下的“子区间”颜色信息应该是一样的,

并且只有这一种颜色如果延时标记记录颜色的编号的话,那么应该这么向下更新

node->xxx->painted =  << (node->state - )

(xxx表示左子树或者右子树,state是延时标记,painted是颜色信息)

  如果不知道左移运算的可以看看下面

a =     

当 a <<= 2后:

a <<  =     

那如果a<<31会发生什么?

a =     

如果超过了它的二进制位这几位就没有了

  这里左移的意义在于将1(有这种颜色)移动到这种颜色对应的位置上,不然会发生可怕

的事情

  这些问题解决了,这道题也就可以做出来了

  附上算得超级慢的源代码:

 /**
* poj.org
* Problem#2777
* Aceepted
* Time:735ms
* Memory:9628k
*/
#include<iostream>
#include<cstdio>
using namespace std;
typedef class TreeNode{
private:
void init(){ //成员初始化
painted = ;
state = ;
left = NULL;
right = NULL;
}
public:
/**
* 用二进制来表示这一段涂过的颜色,
* 1表示涂了的颜色,0表示没有涂的
* 颜色 。用第i位表示第i种颜色
*/
int painted;
int state; //延时标记,更新第i种颜色
int from;
int end;
TreeNode* left;
TreeNode* right;
TreeNode(){ init(); }
TreeNode(int from, int end){
init();
this->from = from;
this->end = end;
}
}TreeNode;
typedef class Tree{
public:
TreeNode* root;
Tree():root(NULL){}
Tree(int size){
root = build(root, , size);
}
void pushUp(TreeNode* node){
node->painted = node->left->painted | node->right->painted;
}
void pushDown(TreeNode* node){ node->left->state = node->state;
node->left->painted = << (node->state - ); node->right->state = node->state;
node->right->painted = << (node->state - ); node->state = ; }
TreeNode* build(TreeNode *root, int from, int end){
root = new TreeNode(from, end);
if(from == end){
root->painted = 0x01;
return root;
}
int mid = (from + end) >> ;
root->left = build(root->left, from, mid);
root->right = build(root->right, mid + , end);
pushUp(root);
return root;
}
void update(TreeNode* now, int from, int end, int value){
if( from <= now->from && end >= now->end ){
now->state = value;
now->painted = << (value - );
return ;
}
if(now->state != ) pushDown(now);
int mid = (now->from + now->end) >> ;
if(end <= mid) update(now->left, from, end, value);
else if(from > mid) update(now->right, from, end, value);
else{
update(now->left, from, mid, value);
update(now->right, mid + , end, value);
}
pushUp(now);
}
int query(TreeNode* now, int from, int end){
if( from <= now->from && end >= now->end ) return now->painted;
if(now->state != ) pushDown(now);
int mid = (now->from + now->end) >> ;
if(end <= mid) return query(now->left, from, end);
else if(from > mid) return query(now->right, from, end);
else{
return query(now->left, from, mid) | query(now->right, mid + , end);
}
}
}Tree;
Tree board;
int len,color,n;
char ch;
int a,b,c;
void _swap(int& a,int& b){
int t = a;
a = b;
b = t;
}
int getSum(int x){
int result = ;
x &= ( << color) - ;
while(x != ){
result++;
x -= x&(-x);
}
return result;
}
int main(){
scanf("%d%d%d",&len,&color,&n);
board = Tree(len);
for(int i = ;i <= n;i++){
cin>>ch;
if(ch == 'C'){
scanf("%d%d%d",&a,&b,&c);
board.update(board.root, a, b, c);
}else{
scanf("%d%d",&a,&b);
if(a > b) _swap(a,b);
int x = board.query(board.root, a, b);
printf("%d\n",getSum(x));
}
}
return ;
}

poj 2777 Count Color - 线段树 - 位运算优化的更多相关文章

  1. poj 2777 Count Color(线段树区区+染色问题)

    题目链接:  poj 2777 Count Color 题目大意:  给出一块长度为n的板,区间范围[1,n],和m种染料 k次操作,C  a  b  c 把区间[a,b]涂为c色,P  a  b 查 ...

  2. poj 2777 Count Color(线段树)

    题目地址:http://poj.org/problem?id=2777 Count Color Time Limit: 1000MS   Memory Limit: 65536K Total Subm ...

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

    Count Color Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 38921   Accepted: 11696 Des ...

  4. Count Color(线段树+位运算 POJ2777)

    Count Color Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 39917 Accepted: 12037 Descrip ...

  5. POJ 2777 Count Color(线段树之成段更新)

    Count Color Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 33311 Accepted: 10058 Descrip ...

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

    题目链接:http://poj.org/problem?id=2777 题意是有L个单位长的画板,T种颜色,O个操作.画板初始化为颜色1.操作C讲l到r单位之间的颜色变为c,操作P查询l到r单位之间的 ...

  7. [poj2777] Count Color (线段树 + 位运算) (水题)

    发现自己越来越傻逼了.一道傻逼题搞了一晚上一直超时,凭啥子就我不能过??? 然后发现cin没关stdio同步... Description Chosen Problem Solving and Pro ...

  8. POJ P2777 Count Color——线段树状态压缩

    Description Chosen Problem Solving and Program design as an optional course, you are required to sol ...

  9. POJ 2777 Count Color(段树)

    职务地址:id=2777">POJ 2777 我去.. 延迟标记写错了.标记到了叶子节点上.. . . 这根本就没延迟嘛.. .怪不得一直TLE... 这题就是利用二进制来标记颜色的种 ...

随机推荐

  1. laravel5.1接收ajax数据

    前台: $.ajax({ type: 'POST', url: '{!! url('aw/data') !!}', data:{'_token':'<?php echo csrf_token() ...

  2. IRC and security tools

    login:::   /msg NickServ identify <password>. join:::   /join #metasploit 浏览器: Tor操作系统: Tails加 ...

  3. 洛谷P1967 货车运输 [noip2013] 图论

    正解:kruskal+LCA 解题报告: 哇真实心痛了...明明都没多少时间了我居然耗了一个上午+一个中午在上面?哭死辽我QAQ果然菜是原罪QAQ 然后这题,我先港下60pts做法趴?话说其实我觉得我 ...

  4. 洛谷P2312 解方程 [noip2014] 数论

    正解:数论 解题报告: 这儿是,传送门qwq 又是很妙的一道题呢,专门用来对付我这种思维僵化了的傻逼的QAQ 首先看题目的数据范围,发现a<=1010000,很大的一个数据范围了呢,那这题肯定不 ...

  5. 牛客练习赛16D K进制 数论(待理解QAQ)

    正解:数论 解题报告: 行吧那就让我一点点推出来趴QAQ

  6. 怎样解决VMware虚拟机无法连接外网问题

    安装上虚拟机之后,再安装上linux之后,有时会出现ping不通物理机的ip和任何外网包括网关的ip的问题.虚拟机的网卡是桥接状态.下面就让我为大家演示下一下,怎么让虚拟机重新ping通物理机. 工具 ...

  7. vue学习之node.js

    Node.js是一个Javascript运行环境(runtime environment),发布于2009年5月,由Ryan Dahl开发,实质是对Chrome V8引擎进行了封装.本文详细介绍了No ...

  8. [git]git版本管理学习记录

    今天看到别人用这玩意记录自己的进度, 我也学习了一下. 1,适当的工具会提升效率 2,关注点还是得放在代码本身上. github/gitignore github提供了各种gitignore文件 有p ...

  9. libSVM简介及核函数模型选择

    1. libSVM简介 训练模型的结构体 struct svm_problem //储存参加计算的所有样本 { int l; //记录样本总数 double *y; //指向样本类别的组数 struc ...

  10. UVALive - 7269 I - Snake Carpet

    思路: 多画画就发现从五的时候可以这么填: 六的时候这么填: 七的时候这么填: 看出规律了吗? 没看出的话再画画把. #include <bits/stdc++.h> using name ...