题意:0~n-1的数组,初始值为0;执行m个操作,每次操作执行后输出当前值为0的连续段的段数。

操作1: p i j : i~j区间的每个元素值减1

操作2: r i j :i~j区间的每个元素值加1,每个r操作之前,一定有个相应的p操作

数据范围:1 <= n <= 108, 0 <= m <= 20000

线段树现在已经成了竞赛选手的基本功,但是我这块好弱,写下这个题解,方便自己以后复习。

分析,这很明显是个用线段树来解的题,但是数据范围太大。注意到操作次数最多只有20000次,假想所有操作都执行结束,会发现很多数组元素实际上是“成段”变化的——把所有操作的两个端点位置标记出来,则两相邻标记点之间(不包括端点)的元素值总是相同的,于是把他们缩为一个点,这样问题得以简化,数据范围大致到了 n < 60100,就可以用线段树来解了。

题解:线段树的结点定义如下:

struct Node{
int cnt, h;//h表示“区间”高度
bool lf, rf;//标记左右端点是不是等于0
}nd[N<<];

结点应当有个左右端点的,为了节省内存没写,写函数的时候把端点作为参数传递就可以了(详见代码)。

cnt表示当前段值为0的连续段段数,lf和rf分别标记当前结点对应区间的左端点和右端点的值是否等于0;h是对该段整体操作的高度,事实上,可以证明h就是该区间的最大高度,因为r操作必然是对应一个之前的p操作,也就是先减后加,那么就不可能出现子结点的h比当前结点的h还大的情况,于是h就是一段区间的最大值。这是个很重要的推论,当查询到一段区间,如果它的h值不为0,就没必要往下查找了,因为不可能找到解;反之,如果该结点的h值为0,那么相当于对整体这一段没有做任何操作,换句话说,对子结点没有任何影响,那么就可以用子结点的值来更新当前结点的值了。

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;
#define N 41000
#define lc (id<<1)
#define rc (id<<1|1) struct Node{
int cnt, h;//h表示"区间高度"
bool lf, rf;//标记左右端点是不是等于0
} nd[N<<]; void build(int l, int r, int id){
nd[id].lf = nd[id].rf = true;
nd[id].cnt = ;
nd[id].h = ;
if(l == r) return;
int mid = l+r>>;
build(l, mid, lc);
build(mid+, r, rc);
} void pushup(int id,int l, int r){
if(nd[id].h != )//根据题目描述,此时这一段肯定没有高度为0的点
{ //r操作一定是取消之前的一个p操作。于是,nd[id].h相当于是这一段的最高高度
nd[id].cnt = ;
nd[id].lf = nd[id].rf = false;
return;
}
if(l == r){
nd[id].cnt = ;
nd[id].lf = nd[id].rf = true;
return;
}
else {//注意还是nd[id].h==0,那此时,这段整体相当于没有操作,根据子节点跟新这一结点的值就可以了
nd[id].lf = nd[lc].lf, nd[id].rf = nd[rc].rf;
nd[id].cnt = nd[lc].cnt + nd[rc].cnt - (nd[lc].rf && nd[rc].lf);
}
} void add(int l, int r, int v, int L, int R, int id)
{
int mid = L+R>>;
if(l <= L && r >= R)
{
nd[id].h += v;
pushup(id, L, R);
return;
}
if(l <= mid) add(l, r, v, L, mid, lc);
if(r > mid) add(l, r, v, mid+, R, rc);
pushup(id, L, R);
}
//-------------------
struct Query{
char op[];
int l, r;
} qry[N>>]; int x[N];
int xcnt;
//-------------------
int main()
{
int T, n, q;
char tm;
int l, r;
scanf("%d", &T);
for(int cas = ; cas <= T; cas++){
scanf("%d %d", &n, &q);
xcnt = ;
x[xcnt++] = ;
x[xcnt++] = n-;
int i;
for(i = ; i < q; i++){
scanf("%s %d %d", qry[i].op, &l, &r);
qry[i].l = l, qry[i].r = r;
x[xcnt++] = l;
x[xcnt++] = r;
}
sort(x, x+xcnt);
xcnt = unique(x, x+xcnt)-x;
for(i = xcnt-; i > ; i--) if(x[i] != x[i-]+) x[xcnt++] = x[i-]+;
/*不这样做的反例
5 2
p 0 1
p 3 4
*/
sort(x, x+xcnt);
build(, xcnt-, );
printf("Case #%d:\n", cas);
for(i = ; i < q; i++){
l = lower_bound(x, x+xcnt, qry[i].l)-x;
r = lower_bound(x, x+xcnt, qry[i].r)-x;
add(l, r, qry[i].op[] == 'p' ? - : , , xcnt-, );
printf("%d\n", nd[].cnt);
}
}
return ;
}

zoj 3325 Machine(线段树)的更多相关文章

  1. HDU 4052 Adding New Machine (线段树+离散化)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4052 初始给你w*h的矩阵,给你n个矩形(互不相交),按这些矩形尺寸把初始的矩形扣掉,形成一个新的'矩 ...

  2. ZOJ - 1610 经典线段树染色问题

    这个是一个经典线段树染色问题,不过题目给的是左右左右坐标,即[0,3]包含0-1这一段 1-2这一段 2-3这一段,和传统的染色不太一样,不过其实也不用太着急. 我们把左边的坐标+1,即可,那么[0, ...

  3. zoj 3349 dp + 线段树优化

    题目:给出一个序列,找出一个最长的子序列,相邻的两个数的差在d以内. /* 线段树优化dp dp[i]表示前i个数的最长为多少,则dp[i]=max(dp[j]+1) abs(a[i]-a[j])&l ...

  4. 线段树区间染色 ZOJ 1610

    Count the Colors ZOJ - 1610 传送门 线段树区间染色求染色的片段数 #include <cstdio> #include <iostream> #in ...

  5. ZOJ 1610 Count the Colors (线段树区间更新)

    题目链接 题意 : 一根木棍,长8000,然后分别在不同的区间涂上不同的颜色,问你最后能够看到多少颜色,然后每个颜色有多少段,颜色大小从头到尾输出. 思路 :线段树区间更新一下,然后标记一下,最后从头 ...

  6. ZOJ 3597 Hit the Target! (线段树扫描线 -- 矩形所能覆盖的最多的点数)

    ZOJ 3597 题意是说有n把枪,有m个靶子,每把枪只有一发子弹(也就是说一把枪最多只能打一个靶子), 告诉你第 i 把枪可以打到第j个靶, 现在等概率的出现一个连续的P把枪,在知道这P把枪之后,你 ...

  7. zoj 3511 Cake Robbery(线段树)

    problemCode=3511" target="_blank" style="">题目链接:zoj 3511 Cake Robbery 题目 ...

  8. ZOJ 1859 Matrix Searching(二维线段树)

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1859 Matrix Searching Time Limit: 10 Seco ...

  9. zoj 1610 Count the Colors(线段树延迟更新)

    所谓的懒操作模板题. 学好acm,英语很重要.做题的时候看不明白题目的意思,我还拉着队友一块儿帮忙分析题意.最后确定了是线段树延迟更新果题.我就欣欣然上手敲了出来. 然后是漫长的段错误.... 第一次 ...

随机推荐

  1. [CSP-S模拟测试]:Dash Speed(线段树+并查集+LCA)

    题目描述 比特山是比特镇的飙车圣地.在比特山上一共有$n$个广场,编号依次为$1$到$n$,这些广场之间通过$n−1$条双向车道直接或间接地连接在一起,形成了一棵树的结构. 因为每条车道的修建时间以及 ...

  2. linux的shell脚本运行python程序

    可以说和windows里的bat是一样的. python3 /opt/pyweibo/get_user_info.py 104501 104502 104503

  3. Visual Studio Code-使用Chrome Debugging for VS Code调试JS

    准备工作 安装 Debugger for Chrome 插件 按 F5(或选择菜单栏的 Debug->Start Debuging),然后选择 Chrome,就会自动创建默认的配置文件 &quo ...

  4. Schema 与数据类型优化

    这是<高性能 MySQL(第三版)>第四章<Schema 与数据类型优化>的读书笔记. 1. 选择优化的数据类型 数据类型的选择原则: 越小越好:选择满足需求的最小类型.注意, ...

  5. 【Unity练习】 平衡球Demo

    链接:http://pan.baidu.com/s/1pKEpnIz 密码:btke

  6. Codeforces 1061C (DP+滚动数组)

    题面 传送门 分析 考虑DP 设\(dp[i][j]\)表示前i个数选出的序列长度为j的方案数 状态转移方程为: \[ dp[i][j]= \begin{cases}dp\left[ i-1\righ ...

  7. Matplotlib基础使用

    matplotlib 一.Matplotlib基础知识 Matplotlib中的基本图表包括的元素 x轴和y轴 axis 水平和垂直的轴线 x轴和y轴刻度 tick 刻度标示坐标轴的分隔,包括最小刻度 ...

  8. hdu6311 Cover (欧拉路径输出)

    hdu6311Cover 题目传送门 题意:有最少用多少条边不重复的路径可以覆盖一个张无向图. 分析:对于一个连通块(单个点除外),如果奇度数点个数为 k,那么至少需要max{k/2,1}  条路径. ...

  9. python print (x,end = '') 意思作用

    for x in range(10) python print(x)换行输出 for x in range(10) python print (x,end = '')  不换行输出

  10. P3826 [NOI2017]蔬菜

    传送门 注意每一单位蔬菜的变质时间是固定的,不随销售发生变化 固定的...... 就是每一个单位的蔬菜在哪一天变质是早就定好了的 发现从第一天推到最后一天很不好搞 考虑反过来,从最后一天推到第一天,这 ...