POJ2777(线段树)Count Color
来源:互联网 发布:淘宝店面装修尺寸 编辑:程序博客网 时间:2024/06/03 00:37
Count Color
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 43131 Accepted: 13068
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.
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
2 2 4C 1 1 2P 1 2C 2 2 2P 1 2
Sample Output
21
题意就是给你L(板块长度),T(颜色种类),O(操作次数),操作分为C和P,C之后跟有3个数A、B、C把区间A-B涂上C颜色。然后P后面跟有A、B,问你区间A-B有多少种颜色。
线段树区间更新,我们可以看到颜色给了30种,很明显是要让我们用二进制表示颜色种类哒嘛,也就是每种颜色有(1)或没有(0),共有2^30 种可能。
这次依旧是先加标记变量,每次更新并不需要更新到叶子结点(表示还试过更新到叶子,表示直接re啊喂,就是要学习lazy!!),具体我会在代码中说,总结很多前辈的经验,然后优化了一些地方。最坑的是要注意看题啊,A还有可能比B大哒!!
#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <queue>#include <map>#include <string>#include <cstring>#include <vector>using namespace std;const int MAXN=100000+10;int n,m,t;struct node{ int l,r; int flag;//记录区间是不是完全覆盖 int colour;//记录结点颜色的种类}tree[MAXN<<2];int f(int x)//返回二进制1的个数{ int sum=0; while(x) { if(x&1)sum++; x>>=1; } return sum;}void build(int i,int l,int r)//建立线段树{ tree[i].l=l; tree[i].r=r; if(l==r)return; int mid=(l+r)>>1; build(i<<1,l,mid); build(i<<1|1,mid+1,r);}void add(int i,int l,int r,int c)//更新线段树{ if(tree[i].l==l&&tree[i].r==r)//找到区间后,标记更新,暂时不向下更新(我试过更新到底直接RE,估计是爆栈了) { tree[i].flag=1; tree[i].colour=1<<(c-1); return ; } if(tree[i].flag) //更新结点的时候,如果这个结点上次应该更新却没有更新,那么需要先向下更新一层结点 //(因为这次更新走到这说明是需要向下更新的,如果之前还不更新,那么父亲结点肯定是会更新错误的) { tree[i].flag=0; tree[i<<1].flag=tree[i<<1|1].flag=1; tree[i<<1].colour=tree[i<<1|1].colour=tree[i].colour; } //然后继续向下更新这次的更新 int mid=(tree[i].l+tree[i].r)>>1; if(r<=mid)add(i<<1,l,r,c); else if(l>mid)add(i<<1|1,l,r,c); else { add(i<<1,l,mid,c); add(i<<1|1,mid+1,r,c); } //向下更新孩子完毕后,注意要向上更新父亲结点!(不要光管下面忘了上面呐) tree[i].colour=tree[i<<1].colour|tree[i<<1|1].colour;}int ask(int i,int l,int r)//查找函数,没有特别好说的{ if(tree[i].l==l&&tree[i].r==r) { return tree[i].colour; } int mid=(tree[i].l+tree[i].r)>>1; if(tree[i].flag)return tree[i].colour; //不仅仅是优化,它下面还有可能没更新呢 if(r<=mid)return ask(i<<1,l,r); else if(l>mid)return ask(i<<1|1,l,r); else return ask(i<<1,l,mid)|ask(i<<1|1,mid+1,r);}int main(){ scanf("%d%d%d",&n,&t,&m); char s[2]; int l,r,c; build(1,1,n); tree[1].flag=1; //开始整个区间就是覆盖颜色1的 tree[1].colour=1; while(m--) { scanf("%s",s); if(s[0]=='C') { scanf("%d%d%d",&l,&r,&c); if(l>r)swap(l,r); //注意!看题目,l可能是大于r哒 add(1,l,r,c); } else { scanf("%d%d",&l,&r); if(l>r)swap(l,r); int ans=f(ask(1,l,r)); printf("%d\n",ans); } } return 0;}
关于颜色更新覆盖问题,肯定是后来者居上,线段树就是大区间在上,如果走不到下面小区间,那么再次更新的时候,大区间就会更新覆盖小区间,然后再去重新更新小区间,最后返回更新大区间。也就是说开始第一次并不向下面的小区间更新,只是记录,下次走到这里的时候,需要用到它的小区间了,那么小区间才会被更新。如果走不到小区间,那么小区间根本不需要更新,大区间标记全覆盖就可以了,下次用到的时候自然会先更新。(这里还是需要大家自己画图多想一想,搞明白,只有深刻理解,才能把它转化为自己的资源再利用~)
1 0
- POJ2777 Count Color(线段树)
- POJ2777(线段树)Count Color
- POJ2777 Count Color(线段树+染色)
- poj2777 Count Color(线段树+状压)
- POJ2777 Count Color 线段树
- 【poj2777】【线段树】Count Color
- [poj2777 Count Color]线段树
- 线段树 POJ2777 Count Color
- POJ2777 Count Color【线段树】
- poj2777 Count Color(线段树)
- POJ2777 Count Color 线段树
- POJ2777 - Count Color (线段树 区间更新)
- [luogu1558][POJ2777]Count Color(线段树+二进制操作)
- 线段树2 POJ2777 Count Color
- POJ2777——Count Color(线段树)
- POJ2777 Count Color 线段树区间更新
- poj2777--Count Color(线段树,二进制转化)
- 线段树 POJ2777 Count Color 解题报告
- SSM 框架整合案例
- LeetCode 102. Binary Tree Level Order Traversal
- IOS NSPredicate 查询、搜索
- 【模拟】Codeforces 671A Recycling Bottles
- Express
- POJ2777(线段树)Count Color
- UVALive 6859
- 关于QwtMust construct a QApplication before a QPaintDevice的问题解决
- OpenCV实现图像暗区扩张(腐蚀图片)
- iOS 开发中的细节知识点之UILabel篇
- 【Consul】Consul实践指导-配置文件
- Redis 3.2.3 安装和启动
- VMware 12 Pro虚拟机安装Ubuntu 16操作系统,选择创建新的虚拟机操作后无反应
- Linxu系统下MySQL常见操作命令详细解读