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:

  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 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以免被坑


  • 线段树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的重要性的更多相关文章

  1. poj 2777(线段树+lazy思想) 小小粉刷匠

    http://poj.org/problem?id=2777 题目大意 涂颜色,输入长度,颜色总数,涂颜色次数,初始颜色都为1,然后当输入为C的时候将x到y涂为颜色z,输入为Q的时候输出x到y的颜色总 ...

  2. POJ 2777(线段树)

    Count Color Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 42507   Accepted: 12856 Des ...

  3. POJ 2777 线段树基础题

    题意: 给你一个长度为N的线段数,一开始每个树的颜色都是1,然后有2个操作. 第一个操作,将区间[a , b ]的颜色换成c. 第二个操作,输出区间[a , b ]不同颜色的总数. 直接线段树搞之.不 ...

  4. poj 2777线段树应用

    敲了n遍....RE愉快的debug了一晚上...发现把#define maxn = 100000 + 10 改成 #define maxn = 100010 就过了....感受一下我呵呵哒的表情.. ...

  5. Count Color POJ - 2777 线段树

    Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds ...

  6. poj 3468(线段树+lazy思想)

    题目链接:http://poj.org/problem?id=3468 思路:如果直接去做,每次都更新到叶子节点,那必然会TLE,我们可以采用lazy的思想:没必要每次更新都更新到叶子节点,只要有一个 ...

  7. POJ 3225 线段树+lazy标记

    lazy写崩了--. 查了好久 /* U-> [l,r]–>1 I-> [1,l-1] [r+1,+无穷] –>0 D-> [l,r]–>0 C-> [1,l ...

  8. poj 2777 线段树的区间更新

    Count Color Time Limit: 1000 MS Memory Limit: 65536 KB 64-bit integer IO format: %I64d , %I64u Java ...

  9. poj 2777 线段树 区间更新+位运算

    题意:有一个长板子,分成多段,有两种操作,第一种是C给从a到b那段染一种颜色c,另一种是P询问a到b有多少种不同的颜色.Sample Input2 2 4  板长 颜色数目 询问数目C 1 1 2P ...

随机推荐

  1. 队列的含义以及C语言实现顺序队列

    队列,和栈一样,也是一种对数据的"存"和"取"有严格要求的线性存储结构. 什么是队列 与栈结构不同的是,队列的两端都"开口",要求数据只能从 ...

  2. Java编程最差实践常见问题详细说明(2)转

    Java编程最差实践常见问题详细说明(2)转 2012-12-13 13:57:20|  分类: JAVA |  标签:java  |举报|字号 订阅     反射使用不当  错误的写法: Java代 ...

  3. iOS技能 - 最新美团、百度、腾讯、头条、阿里 面试题目记录

    关于面试题,可能没那么多时间来总结答案,有什么需要讨论的地方欢迎大家指教.主要记录一下准备过程,和面试的一些总结,希望能帮助到正在面试或者将要面试的同学吧. 美团 一面 1.简历上写的项目问了一遍,然 ...

  4. hexo部署在码云中 无样式问题

    在本地localhost:4000 运行如下 上传码云之后打开Gitee Pages服务 如下 同时控制台打印 解决方法 找到根目录下的_config.yml中的url 和 root # url: h ...

  5. 记录d3.js 力导向图的平移缩放,类似地图导航点击某一项移动到当前位置

    项目中有用到d3.js用于图结构的查询, 需求如下: 右上角有个模糊搜索功能,查询出来的结果用列表展示 点击列表的某一列,要求画布移动到当前选中的节点的位置,基于画布正中间 搜索出来的结果列表展示用的 ...

  6. 如何批量修改文件后缀名,python来帮你

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取http ...

  7. 三个步骤就能让你轻松掌握Python爬虫

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:NicePython PS:如有需要Python学习资料的小伙伴可以加 ...

  8. stand up meeting 12-3

    因为前后端在参数传递定义不清晰的原因,今天士杰和国庆采用了pair programming的方法,在一台电脑前工作了四十分钟,明确了请求questionpool,请求question,请求rank d ...

  9. F 最大公约数和最小公倍数问题

    链接:https://ac.nowcoder.com/acm/contest/948/F来源:牛客网 输入2个正整数x0,y0(2<=x0<100000,2<=y0<=1000 ...

  10. tensorflow-参数、超参数、卷积核权值共享

    根据网上查询到的说法,参数就是在卷积神经网络中可以被训练的参数,比如卷积核的权值和偏移等等,而超参数是一些预先设定好并且无法改变的,比如说是卷积核的个数等. 另外还有一个最最基础的概念,就是卷积核的权 ...