Codeforces 193 D. Two Segments(线段树)

机智的线段树题,

参考了这个题解http://www.cnblogs.com/keam37/p/4335914.html

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long ll;

#define lson(x) ((x<<1)+1)
#define rson(x) ((x<<1)+2)

const int N = 300005;

int n, v[N], p[N];

struct Node {
    int l, r, Min, lazy, val1, val2;
    void gao(int x) {
        lazy += x;
        Min += x;
    }
} node[N * 4];

void build(int l, int r, int x = 0) {
    node[x].l = l; node[x].r = r;
    node[x].Min = node[x].lazy = node[x].val2 = 0;
    node[x].val1 = r - l + 1;
    if (l == r) return;
    int mid = (l + r) / 2;
    build(l, mid, lson(x));
    build(mid + 1, r, rson(x));
}

void pushdown(int x) {
    if (node[x].lazy) {
       node[lson(x)].gao(node[x].lazy);
       node[rson(x)].gao(node[x].lazy);
    }
    node[x].lazy = 0;
}

void pushup(int x) {
    node[x].Min = min(node[lson(x)].Min, node[rson(x)].Min);
    node[x].val1 = (node[lson(x)].Min == node[x].Min) * node[lson(x)].val1 + (node[rson(x)].Min == node[x].Min) * node[rson(x)].val1;
    node[x].val2 = (node[lson(x)].Min == node[x].Min + 1) * node[lson(x)].val1 + (node[rson(x)].Min == node[x].Min + 1) * node[rson(x)].val1;
    node[x].val2 += (node[lson(x)].Min == node[x].Min) * node[lson(x)].val2 + (node[rson(x)].Min == node[x].Min) * node[rson(x)].val2;
}

void add(int l, int r, int val, int x = 0) {
    if (node[x].l >= l && node[x].r <= r) {
        node[x].gao(val);
        return;
    }
    pushdown(x);
    int mid = (node[x].l + node[x].r) / 2;
    if (l <= mid) add(l, r, val, lson(x));
    if (r > mid) add(l, r, val, rson(x));
    pushup(x);
}

ll ans;

void query(int l, int r, int x = 0) {
    if (node[x].l >= l && node[x].r <= r) {
         if (node[x].Min == 1) {
            ans += node[x].val1 + node[x].val2;
         } else if (node[x].Min == 2)
            ans += node[x].val1;
         return;
    }
    pushdown(x);
    int mid = (node[x].l + node[x].r) / 2;
    if (l <= mid) query(l, r, lson(x));
    if (r > mid) query(l, r, rson(x));
    pushup(x);
}

int main() {
    scanf("%d", &n);
    int tmp;
    for (int i = 1; i <= n; i++) {
        scanf("%d", &tmp);
        v[tmp] = i;
    }
    ans = 0;
    build(1, n);
    memset(p, 0, sizeof(p));
    for (int i = n; i >= 1; i--) {
        p[v[i]] = i;
        int x = p[v[i] - 1], y = p[v[i] + 1];
        if (x > y) swap(x, y);
        if (x) {
            add(i, x - 1, 1);
            add(y, n, -1);
        } else if (y) add(i, y - 1, 1);
        else add(i, n, 1);
        query(i, n);
    }
    printf("%I64d\n", ans - n);
    return 0;
}
时间: 2024-10-07 05:45:34

Codeforces 193 D. Two Segments(线段树)的相关文章

Codeforces 610D Vika and Segments 线段树+离散化+扫描线

可以转变成上一题(hdu1542)的形式,把每条线段变成宽为1的矩形,求矩形面积并 要注意的就是转化为右下角的点需要x+1,y-1,画一条线就能看出来了 #include<bits/stdc++.h> #define pi acos(-1.0) #define ll long long #define mod 1000000007 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #pragma comment(linker,

POJ 1436 Horizontally Visible Segments (线段树&amp;#183;区间染色)

题意   在坐标系中有n条平行于y轴的线段  当一条线段与还有一条线段之间能够连一条平行与x轴的线不与其他线段相交  就视为它们是可见的  问有多少组三条线段两两相互可见 先把全部线段存下来  并按x坐标排序  线段树记录相应区间从右往左当前可见的线段编号(1...n)  超过一条就为0  然后从左往右对每条线段  先查询左边哪些线段和它是可见的  把可见关系存到数组中  然后把这条线段相应区间的最右端可见编号更新为这条线段的编号  最后暴力统计有多少组即可了 #include <cstdio>

Poj1436Horizontally Visible Segments线段树

#include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <set> #include <qu

Codeforces 444C DZY Loves Colors(线段树)

题目大意:Codeforces 444C DZY Loves Colors 题目大意:两种操作,1是修改区间上l到r上面德值为x,2是询问l到r区间总的修改值. 解题思路:线段树模板题. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; const int maxn = 5*1e5; typedef long lo

Codeforces 57B Martian Architecture 暴力||线段树

题目链接:点击打开链接 题意:n长的序列(初始全为0) m个操作 k个查询 下面m个操作[l,r] h 代表 a[l] +=h; a[l+1] += h+i; a[l+i] += h+i;  l<=i<=r 然后问k个位置的和 因为k<=100 所以直接暴力也可以 ----------------------- 如果k<=100000 也是可以做的 只需要给区间记录一个标记lazy,表示从左端点开始 l, l+1, l+i ··· l+r 而向下更新时, 左区间则直接更新, 右区间

Codeforces Round #337 (Div. 2) D. Vika and Segments 线段树 矩阵面积并

D. Vika and Segments Vika has an infinite sheet of squared paper. Initially all squares are white. She introduced a two-dimensional coordinate system on this sheet and drew n black horizontal and vertical segments parallel to the coordinate axes. All

codeforces 487B B. Strip(rmq+线段树+二分)

题目链接: codeforces 487B 题目大意: 给出一个序列,要把序列划分成段,每一段最少有L个元素,段中的最大元素和最小元素之差不大于s,问划分的段的最少的数量是多少. 题目分析: 首先用rmq维护区间最大值和区间最小值. 然后按顺序扫描数组,线段树维护的数组,每个记录当前点作为最后一个点的前i个点划分的最小的段数,那么每次更新就是二分找到可以转移到我的最远距离,然后再选取与我距离大于l的那部分,取最小值即可. 最终结果就是线段树维护的数组的最后一个位置的元素的值. AC代码: #in

codeforces 482B. Interesting Array【线段树区间更新】

题目:codeforces 482B. Interesting Array 题意:给你一个值n和m中操作,每种操作就是三个数 l ,r,val.就是区间l---r上的与的值为val,最后问你原来的数组是多少?如果不存在输出no 分析:分析发现要满足所有的区间,而一个点上假如有多个区间的话,这个点的值就是所有区间或的值,因为只有这样才能满足所有区间的,把所有位上的1都保存下来了,那么可以发现用线段树来维护,但是那么怎么判断满不满足条件呢?可以也用线段树,更新了之后在整个维护一遍看看满不满足题意,如

Codeforces GYM 100114 D. Selection 线段树维护DP

D. Selection Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Description When selecting files in an application dialog, Vasya noted that he can get the same selection in different ways. A simple mouse click selects a sing