codedecision P1112 区间连续段 题解 线段树

题目描述:https://www.cnblogs.com/problems/p/P1112.html
题目链接:http://codedecision.com/problem/1112
线段树区间操作,每一个线段对应的点包含三个信息:

  • \(l\):表示这个区间最左边的点的数值;
  • \(r\):表示这个区间最右边的点的数值;
  • \(cnt\):表示这个区间有多少个数值段。

合并的时候:

  • 根节点的 \(l\) 值等于左儿子节点的 \(l\) 值;
  • 根节点的 \(r\) 值等于右儿子节点的 \(r\) 值;
  • 根节点的 \(cnt\) 值取决于左儿子的 \(r\) 值和右儿子的 \(l\) 值是否相等,
    1. 如果相等,则为:左儿子的 \(cnt\) + 右儿子的 \(cnt\) - 1
    2. 否则,为:左儿子的 \(cnt\) + 右儿子的 \(cnt\)

更新的时候,如果节点表示的这一段区间全在区间范围内,
则将节点的 \(l\) 和 \(r\) 都置为将要更新的值,并将节点的 \(cnt\) 置为 1。

因为涉及区间操作,需要用到延迟操作。
实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100100;
struct Node {
    int l, r, cnt;
    Node () {}
    Node (int _l, int _r, int _cnt) { l = _l; r = _r; cnt = _cnt; }
} tree[maxn<<2];
int n, lazy[maxn<<2];
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1
void push_up(int rt) {
    tree[rt].l = tree[rt<<1].l;
    tree[rt].r = tree[rt<<1|1].r;
    tree[rt].cnt = tree[rt<<1].cnt + tree[rt<<1|1].cnt - (tree[rt<<1].r == tree[rt<<1|1].l ? 1 : 0);
}
void push_down(int rt) {
    if (lazy[rt]) {
        lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
        tree[rt<<1].cnt = tree[rt<<1|1].cnt = 1;
        tree[rt<<1].l = tree[rt<<1].r = tree[rt<<1|1].l = tree[rt<<1|1].r = lazy[rt];
        lazy[rt] = 0;
    }
}
void build(int l, int r, int rt) {
    if (l == r) {
        tree[rt] = Node(0, 0, 1);
        return;
    }
    int mid = (l + r) / 2;
    build(lson);
    build(rson);
    push_up(rt);
}
void update(int L, int R, int v, int l, int r, int rt) {
    if (l > r) {
        printf("fuck %d > %d (%d)\n", l, r, rt);
        return;
    }
    if (rt >= maxn*2) {
        printf("fuck rt big %d , %d (%d)\n", l, r, rt);
        return;
    }
    if (L <= l && r <= R) {
        tree[rt] = Node(v, v, 1);
        lazy[rt] = v;
        return;
    }
    push_down(rt);
    int mid = (l + r) / 2;
    if (L <= mid) update(L, R, v, lson);
    if (R > mid) update(L, R, v, rson);
    push_up(rt);
}
Node query(int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) return tree[rt];
    push_down(rt);
    int mid = (l + r) / 2;
    if (L > mid) return query(L, R, rson);
    else if (R <= mid) return query(L, R, lson);
    else {
        Node a = query(L, R, lson);
        Node b = query(L, R, rson);
        return Node(a.l, b.r, a.cnt + b.cnt - (a.r == b.l ? 1 : 0));
    }
}
int m, x, y, a;
string op;
int main() {
    cin >> n >> m;
    build(1, n, 1);
    while (m --) {
        cin >> op;
        if (op == "update") {
            cin >> x >> y >> a;
            update(x, y, a, 1, n, 1);
        }
        else {
            cin >> x >> y;
            cout << query(x, y, 1, n, 1).cnt << endl;
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/codedecision/p/11785168.html

时间: 2024-08-02 09:45:48

codedecision P1112 区间连续段 题解 线段树的相关文章

SPOJ 1043 Can you answer these queries I 求任意区间最大连续子段和 线段树

题目链接:点击打开链接 维护区间左起连续的最大和,右起连续的和.. #include <cstdio> #include <iostream> #include <algorithm> #include <string.h> #include <math.h> #include <vector> #include <map> using namespace std; #define N 50050 #define Lson

区间求最值 线段树

湖南师范大学 11460 区间求最值 区间求最值   Problem description   给定一个长度为N 的数组,有q个询问,每个询问是求在数组的一段区间内那个元素的因子的个数最大,比如24的因子的个数就是8.  Input   首先是一个整数t,表示有t组测试数据,每组测试数据的第一行是一个整数N(1<=N<=10^6),第二行有N个整数ai(1<=ai<=10^6,i=1,2,.....N)表示数组的元素.第三行有一个整数q(1<=q<=10^5),代表有

POJ2182题解——线段树

POJ2182题解——线段树 2019-12-20 by juruoOIer 1.线段树简介(来源:百度百科) 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN).而未优化的空间复杂度为2N,实际应用时一般还要开4N的数组以免越界,因此有时需要离散化让空间压缩. 2.线段树实际应用 上面的都是些基本的线段树结构,但只有这些并不能做什么,就好比一个程序有

理想乡题解 (线段树优化dp)

题面 思路概述 首先,不难想到本题可以用动态规划来解,这里就省略是如何想到动态规划的了. 转移方程 f[i]=min(f[j]+1)(max(i-m,0)<=j<i 且j符合士兵限定) 注意要用 max(i-m,0)以防止越界 我们先用两个数组sl,sa分别统计1~i个士兵中有多少个Lencer和Archer 然后在max(i-m,0)中寻找符合条件的j (1).两种士兵相差不超过k. 这个好说abs((sl[i]-sl[j])-(sa[i]-sa[j]))<=k 不要忘了第二种情况!!

敌兵布阵_区间求和问题_线段树 or 树状数组

敌兵布阵 TimeLimit: 2000/1000 MS (Java/Others)  MemoryLimit: 65536/32768 K (Java/Others) 64-bit integer IO format:%I64d Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况.由于采取了某种先进的监测手段,所

区间的价值(线段树)百度之星

区间的价值 Accepts: 0 Submissions: 0 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem Description 我们定义“区间的价值”为一段区间的最大值*最小值. 一个区间左端点在LLL,右端点在RRR,那么该区间的长度为(R−L+1)(R-L+1)(R−L+1). 现在聪明的杰西想要知道,对于长度为kkk的区间,最大价值的区间价值是多少.

最大连续和(线段树+分治)

最大连续和 Time Limit: 1000 MS Memory Limit: 32768 K Total Submit: 61(13 users) Total Accepted: 15(9 users) Rating: Special Judge: No Description 给出一个长度为n的整数序列D,你的任务是对m个询问做出回答.对于询问(a,b),需要找到 两个下标x和y,使得a<=x<=y<=b,并且Dx+Dx+1+....+Dy尽量大.如果有多组满足条件的x和y,x 应尽

Vijos1448题解---线段树+括号法

描述 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:K=1,K=1,读入l.r表示在区间[l,r]中种上一种树,每次操作种的树的种类都不同K=2,读入l,r表示询问l~r之间能见到多少种树(l,r>0) 输入格式 第一行n,m表示道路总长为n,共有m个操作接下来m行为m个操作 输出格式 对于每个k=2输出一个答案 样例输入 5 4 1 1 3 2 2 5 1 2 4 2 3 5

Codeforces 527C Glass Carving (最长连续0变形+线段树)

Leonid wants to become a glass carver (the person who creates beautiful artworks by cutting the glass). He already has a rectangular w mm ?×? h mm sheet of glass, a diamond glass cutter and lots of enthusiasm. What he lacks is understanding of what t