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. Python设计模式(9)-外观模式

    # /*外观模式:为外界调用提供一个统一的接口,把其他类中需要用到的方法提取# * 出来,由外观类进行调用.然后在调用段实例化外观类,以间接调用需要的# * 方法.这种方式和代理模式有异曲同工之妙.然 ...

  2. 六、路由详细介绍之动态路由RIP(了解一下就行)

    动态路由分为距离矢量路由(RIP)和链路状态(OSPF和ISIS) 一.离矢量路由协议-RIP RIP协议现在基本上被淘汰. RIP动态路由协议工作原理,如上图: R12中有192.168.1.0和1 ...

  3. python初学(二)

    1.输入一个整数列表L,判断L中是否存在相同的数字: (1)若存在,输出YES,否则输出NO: (2)若存在,输出YES,同时输出相同的数字:否则输出NO. l=list(input()) print ...

  4. Linux 下发送邮件

    由于种种原因,需要由我这个兼职运维每天发送对账单文件给运营同学,故研究下 Linux 发送邮件,希望对大家有所帮助. 安装 # Centos,安装 mailx $ yum install -y mai ...

  5. Android应用架构分析

    一.res目录: 1.属性:Android必需: 2.作用:存放Android项目的各种资源文件.这些资源会自动生成R.java. 2.1.layout:存放界面布局文件. 2.2.strings.x ...

  6. F - Robot Motion 栈加BFS

    A robot has been programmed to follow the instructions in its path. Instructions for the next direct ...

  7. Flask基础-01.Flask简介

    Flask简介 Web应用程序作用 Web(World Wide Web)诞生最初的目的,是为了利用互联网交流工作文档. 关于Web框架 1. 什么是Web框架? 1. 已经封装好了一段代码,协助程序 ...

  8. 如何在Ubuntu 18.04上安装Nginx

    Nginx功能之强大,想必大家比我更清楚. 百度百科:Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务.Nginx是由伊戈尔 ...

  9. sublime查看项目代码多少行

    ---------------------sublime   0.右击要查找的文件; 1.勾选正则( .* ); 3.输入正则表达式 ^[ \t]*[^ \t\n\r]+.*$ 0:搜索 \n 是不是 ...

  10. mybatis源码学习:从SqlSessionFactory到代理对象的生成

    目录 一.根据XML配置文件构建SqlSessionFactory 二.通过SqlSessionFactory创建SqlSession 三.getMapper获取动态代理对象 一.根据XML配置文件构 ...