POJ 2777——线段树Lazy的重要性
POJ 2777 Count Color ——线段树Lazy的重要性
原题
链接:http://poj.org/problem?id=2777
Count Color
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 59087 Accepted: 17651
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:
- "C A B C" Color the board from segment A to segment B with color C.
- "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 4
C 1 1 2
P 1 2
C 2 2 2
P 1 2
Sample Output
2
1
Source
POJ Monthly--2006.03.26,dodo
思路
- 题目大意
一开始我们有一段长为L的序列,其上每个数都为1,之后我们要处理o个操作,一种是将一个区间全部修改为另一个数,另一种是给我们一个区间,要求我们算出这个区间内有多少种不同的数,每个数的值小于30
思路
- 1.一看区间问题,首先想到了线段树
- 2.发现种类数量不符合区间加法,但是我想到了set去重
- 3.但是又想到这个去重,会让复杂度变成约 \(O(o*L*log_2n)\), 这对于1e5量级的L与o是绝对不可以的
- 不过又发现每个数最大为30,那便想到了用二进制来表示一个区间内有多少种数——第几位为1表示这个区间内存在几,而最终我们拆分这个二进制数,统计1的个数就能得出答案。区间合并的时候,用 “或|” 就可以完美地将两个区间的信息合并而不用担心去重的问题。
- 还要注意每次区间操作时,先检查左右端点值,保证l <= r以免被坑
- 1.一看区间问题,首先想到了线段树
线段树code:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
long long ff[400005];
int n, t, oo;
long long qu(int o, int l, int r, int x, int y)
{
if (l >= x && r <= y)
{
return ff[o];
}
int mid = (l + r) >> 1;
long long ans1 = 0;
long long ans2 = 0;
if (x <= mid)
{
ans1 = qu(o << 1, l, mid, x, y);
}
if (y > mid)
{
ans2 = qu(o << 1 | 1, mid + 1, r, x, y);
}
return ans2 | ans1;
}
void ch(int o, int l, int r, int x, int y, int v)
{
if (l == r)
{
ff[o] = (1 << (v - 1));
return;
}
int mid = (l + r) >> 1;
if (x <= mid)
{
ch(o << 1, l, mid, x, y, v);
}
if (y > mid)
{
ch(o << 1 | 1, mid + 1, r, x, y, v);
}
ff[o] = ff[o << 1] | ff[o << 1 | 1];
}
int main()
{
scanf("%d%d%d", &n, &t, &oo);
for (int i = 1; i <= 4 * n; ++i)
{
ff[i] = 1;
}
while (oo--)
{
char cc;
scanf("\n%c", &cc);
if (cc == 'C')
{
int ll, rr, tt;
scanf("%d%d%d", &ll, &rr, &tt);
if (ll > rr)
{
int tt = rr;
rr = ll;
ll = tt;
}
ch(1, 1, n, ll, rr, tt);
}
else
{
int ll, rr;
scanf("%d%d", &ll, &rr);
if (ll > rr)
{
int tt = rr;
rr = ll;
ll = tt;
}
long long cco = qu(1, 1, n, ll, rr);
int co = 0;
while (cco)
{
if (cco & 1)
{
++co;
}
cco >>= 1;
}
printf("%d\n", co);
}
}
return 0;
}
这结束了吗?

我一开始感到一阵不解,因为计算次数最多是 o*t 约等于 3e6 的量级,不过看这复杂度,,很是危险
好吧缺了些东西,这就是线段树的lazy标记,因为我们没有设置lazy标记,所以导致冗余计算很多,lazy标记的加入也较为简单,新开4*L的数组空间,在修改操作的区间包含当前区间时,进行标记,并且在其他操作之前进行下放即可,这一操作可以减少大量的计算,是一种不可缺少的优化
AC代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
int ff[400005], ad[400005];
int n, t, oo;
void pd(int o)
{
ad[o << 1] = ad[o];
ad[o << 1 | 1] = ad[o];
ff[o << 1] = ad[o];
ff[o << 1 | 1] = ad[o];
ad[o] = 0;
}
int qu(int o, int l, int r, int x, int y)
{
if (l >= x && r <= y)
{
return ff[o];
}
if (ad[o])
{
pd(o);
}
int mid = (l + r) >> 1;
int ans1 = 0;
int ans2 = 0;
if (x <= mid)
{
ans1 = qu(o << 1, l, mid, x, y);
}
if (y > mid)
{
ans2 = qu(o << 1 | 1, mid + 1, r, x, y);
}
return ans2 | ans1;
}
void ch(int o, int l, int r, int x, int y, int v)
{
if (l >= x && y >= r)
{
ff[o] = (1 << (v - 1));
ad[o] = (1 << (v - 1));
return;
}
if (ad[o])
{
pd(o);
}
int mid = (l + r) >> 1;
if (x <= mid)
{
ch(o << 1, l, mid, x, y, v);
}
if (y > mid)
{
ch(o << 1 | 1, mid + 1, r, x, y, v);
}
ff[o] = ff[o << 1] | ff[o << 1 | 1];
}
int main()
{
scanf("%d%d%d", &n, &t, &oo);
for (int i = 1; i <= 4 * n; ++i)
{
ff[i] = 1;
}
while (oo--)
{
char cc;
scanf("\n%c", &cc);
if (cc == 'C')
{
int ll, rr, tt;
scanf("%d%d%d", &ll, &rr, &tt);
if (ll > rr)
{
int tt = rr;
rr = ll;
ll = tt;
}
ch(1, 1, n, ll, rr, tt);
}
else
{
int ll, rr;
scanf("%d%d", &ll, &rr);
if (ll > rr)
{
int tt = rr;
rr = ll;
ll = tt;
}
int cco = qu(1, 1, n, ll, rr);
int co = 0;
while (cco)
{
if (cco & 1)
{
++co;
}
cco >>= 1;
}
printf("%d\n", co);
}
}
return 0;
}
数据结构在可行的范围内能优化就要优化,不能抱有侥幸心理而增加自己的WA,用线段树处理区间修改类问题时,一定要考虑能否用标记来优化。
POJ 2777——线段树Lazy的重要性的更多相关文章
- poj 2777(线段树+lazy思想) 小小粉刷匠
http://poj.org/problem?id=2777 题目大意 涂颜色,输入长度,颜色总数,涂颜色次数,初始颜色都为1,然后当输入为C的时候将x到y涂为颜色z,输入为Q的时候输出x到y的颜色总 ...
- POJ 2777(线段树)
Count Color Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 42507 Accepted: 12856 Des ...
- POJ 2777 线段树基础题
题意: 给你一个长度为N的线段数,一开始每个树的颜色都是1,然后有2个操作. 第一个操作,将区间[a , b ]的颜色换成c. 第二个操作,输出区间[a , b ]不同颜色的总数. 直接线段树搞之.不 ...
- poj 2777线段树应用
敲了n遍....RE愉快的debug了一晚上...发现把#define maxn = 100000 + 10 改成 #define maxn = 100010 就过了....感受一下我呵呵哒的表情.. ...
- Count Color POJ - 2777 线段树
Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds ...
- poj 3468(线段树+lazy思想)
题目链接:http://poj.org/problem?id=3468 思路:如果直接去做,每次都更新到叶子节点,那必然会TLE,我们可以采用lazy的思想:没必要每次更新都更新到叶子节点,只要有一个 ...
- POJ 3225 线段树+lazy标记
lazy写崩了--. 查了好久 /* U-> [l,r]–>1 I-> [1,l-1] [r+1,+无穷] –>0 D-> [l,r]–>0 C-> [1,l ...
- poj 2777 线段树的区间更新
Count Color Time Limit: 1000 MS Memory Limit: 65536 KB 64-bit integer IO format: %I64d , %I64u Java ...
- poj 2777 线段树 区间更新+位运算
题意:有一个长板子,分成多段,有两种操作,第一种是C给从a到b那段染一种颜色c,另一种是P询问a到b有多少种不同的颜色.Sample Input2 2 4 板长 颜色数目 询问数目C 1 1 2P ...
随机推荐
- python3(二十一) pip
先确保安装了windows的Python的pip 出现上图说明安装了,命令未找到则没有安装 安装一个图形处理的第三方库 Anaconda安装第三方库 我们经常需要用到很多第三方库,如MySQL驱动程序 ...
- idea打包报错Cleaning up unclosed ZipFile for archive D:\m2\commons-beanutils\commons-beanutils\1.9.2\...
关于idea的打包报错:Cleaning up unclosed ZipFile for archive D:\m2\commons-beanutils\commons-beanutils\1.9.2 ...
- sprigboot 异常 Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].Tomc...
java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start com ...
- group_concat有长度限制
group_concat有长度限制 group_concat 详细用法请点此链接. group_concat有长度限制!长度陷阱用了group_concat后,select里如果使用了li ...
- AJ学IOS(38)UI之核心动画简介
AJ分享,必须精品 核心动画(简介) Core Animation,中文翻译为核心动画,它是一组非常强大的动画处理API,使用它能做出非常炫丽的动画效果,而且往往是事半功倍.也就是说,使用少量的代码就 ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(三)之Everything Is an Object
---恢复内容开始--- Both C++ and Java are hybird languages. A hybird language allow multiple programming st ...
- 用Taro做个微信小程序Todo, 小白工作记录
微信小程序框架: Taro 做微信小程序的框架, 几个比较主流的: 官方的WePY: https://tencent.github.io/wepy/document.html#/ 美团的mpvue: ...
- C - Infinite Fence -1260C
考虑区间长度,我们让r和b除以他们的__gcd这样,这样得到的r和b是互质或者相等的.我们取他们两个小的那个.假设是b.那么被涂的方块应该是b,2b,3b,4b,....kb. 相邻的两个方块之间的区 ...
- 在数组添加元素时报错:IndexError: list index out of range
今天第一次发随笔还有许多不足之处,欢迎评论!!! 最近在写一个成语接龙的小游戏,结果在数组添加元素时报错:IndexError: list index out of range 源码: import ...
- JavaScript数据类型 —— 基础语法(2)
JavaScript基础语法(2) 数据类型 js中有六种数据类型,包括五种基本数据类型(Number,String,Boolean,Undefined,Null),和一种复杂数据类型(Object) ...