[wikioi]线段树练习 2

http://codevs.cn/problem/1081/

#include <vector>
#include <iostream>
#include <string.h>

using namespace std;

const int MAXN = 100000;

struct Line {
    int left, right;
    int n;
};

Line tree[MAXN * 3];

void buildtr(int left, int right, int k) {
    tree[k].left = left;
    tree[k].right = right;
    tree[k].n = 0;
    if (left == right) return;
    int mid = (left + right) / 2;
    buildtr(left, mid, k * 2);
    buildtr(mid + 1, right, k * 2 + 1);
}

int query(int x, int k) {
    if (tree[k].left == x && tree[k].right == x) {
        return tree[k].n;
    }
    int mid = (tree[k].left + tree[k].right) / 2;
    if (x <= mid) return query(x, k * 2);
    else return query(x, k * 2 + 1);
}

int query(int l, int r, int k) {
    if (tree[k].left == l && tree[k].right == r) {
        //cout << "k:" << k << ",l" << l << "r," << r << ",n:" << tree[k].n << endl;
        return tree[k].n;
    }
    int mid = (tree[k].left + tree[k].right) / 2;
    if (r <= mid) {
        return query(l, r, k * 2);
    } else if (l > mid) {
        return query(l, r, k * 2 + 1);
    } else {
        return query(l, mid, k * 2) + query(mid + 1, r, k * 2 + 1);
    }
}

int update(int x, int y, int k) {
    int diff = 0;
    if (tree[k].left == x && tree[k].right == x) {
        diff = y - tree[k].n;
        tree[k].n = y;
        return diff;
    }
    int mid = (tree[k].left + tree[k].right) / 2;
    if (x <= mid) {
        diff = update(x, y, k * 2);
    } else {
        diff = update(x, y, k * 2 + 1);
    }
    tree[k].n += diff;
    return diff;
}

int add(int l, int r, int x, int k) {
    int diff = 0;
    if (tree[k].left == tree[k].right) {
        diff = x;
        tree[k].n += x;
        //cout << "diff:" << x << endl;
        return x;
    }
    int mid = (tree[k].left + tree[k].right) / 2;
    if (mid >= r) {
        diff = add(l, r, x, k * 2);
    } else if (mid < l) {
        diff = add(l, r, x, k * 2 + 1);
    } else {
        diff += add(l, mid, x, k * 2);
        diff += add(mid + 1, r, x, k * 2 + 1);
    }
    tree[k].n += diff;
    return diff;
}

int main() {
    int n;
    cin >> n;
    memset(tree, sizeof(tree), 0);
    buildtr(1, n, 1);
    for (int i = 1; i <= n; i++) {
        int x;
        cin >> x;
        update(i, x, 1);
    }
    int m;
    cin >> m;
    while (m--) {
        int c;
        cin >> c;
        if (c == 1) {
            int a, b, x;
            cin >> a >> b >> x;
            add(a, b, x, 1);
        } else if (c == 2) {
            int i;
            cin >> i;
            int res = query(i, i, 1);
            cout << res << endl;
        }
    }
}

  

时间: 2024-10-13 03:39:38

[wikioi]线段树练习 2的相关文章

[wikioi]线段树练习

http://codevs.cn/problem/1080/ #include <vector> #include <iostream> #include <string.h> using namespace std; const int MAXN = 100000; struct Line { int left, right; int n; }; Line tree[MAXN * 3]; void buildtr(int left, int right, int k)

wikioi 1282 约瑟夫问题 线段树

和上一题一样,寻找第K个位置,只不过需要处理一下下一个位置在哪,画图看看就知道了. #include <cstdio> #include <algorithm> #include <iostream> using namespace std; #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 const int maxn = 30000+5; int sum[max

Wikioi 1081 线段树练习2

线段树练习飘逸的写法,自从自己改成这种写法之后,线段树就没再练过,现在终于练得上了. 因为这里查询只是查询了叶子结点,所以pushUp函数就用不上了,不过我没去掉之前是3ms,去掉之后反而变成4ms了,搞不懂怎么原因,没用到,去掉之后应该更快才对啊,竟然变慢了,真搞不明白? #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <dequ

Wikioi 1082线段树成段更新成段查询

这题从昨晚搞到现在敲了又改好久,刚开始是update中错了,然后找到了.但是还错,然后因为题目没有数据的范围提示,所以弄了好久都不知道哪错了,最后看评论才知道是超int了,改了之后还有错,然后才发现虽然改成long long了,但是输出的时候没改,哈哈-- #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <deque> #in

wikioi 1080 线段树练习 树状数组

1080 线段树练习 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 一行N个方格,开始每个格子里都有一个整数.现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[a,b]中所有元素的和:修改的规则是指定某一个格子x,加上或者减去一个特定的值A.现在要求你能对每个提问作出正确的回答.1≤N<100000,,提问和修改的总数m<10000条. 输入描述 Input Description 输入文件第一行为一个整

Wikioi 2492 树状数组+并查集(单点更新区间查询)

刚开始做的时候用线段树做的,然后就跳进坑里了--因为要开方,所以区间的值都得全部变,然后想用lazy标记的,但是发现用不了,单点更新这个用不了,然后就不用了,就T了.然后实在不行了,看了别人的题解,原来是用树状数组+并查集的方法,唉--没想到啊! 因为开方之后多次那个数就会变成1了,所以是1的时候开方下去就没用了.树状数组更新的时候就把其更新的差更新即可,太机智了这题-- 昨天做了,然后出错找了好久都找不出来,原来是把s[i]写成c[i]了,然后答案一直错,晕-- #include <iostr

小结:线段树 &amp; 主席树

概要: 就是用来维护区间信息,然后各种秀智商游戏. 应用: 优化dp.主席树等. 技巧及注意: size值的活用:主席树就是这样来的.支持区间加减,例题和模板:主席树,[BZOJ]1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树),[BZOJ]1901: Zju2112 Dynamic Rankings(区间第k小+树状数组套可持久化线段树(主席树)) 01(就是更新和不更新等这种对立操作)情况:我们就要在各个更新的操作中明白

[poj2104]可持久化线段树入门题(主席树)

解题关键:离线求区间第k小,主席树的经典裸题: 对主席树的理解:主席树维护的是一段序列中某个数字出现的次数,所以需要预先离散化,最好使用vector的erase和unique函数,很方便:如果求整段序列的第k小,我们会想到离散化二分和线段树的做法, 而主席树只是保存了序列的前缀和,排序之后,对序列的前缀分别做线段树,具有差分的性质,因此可以求任意区间的第k小,如果主席树维护索引,只需要求出某个数字在主席树中的位置,即为sort之后v中的索引:若要求第k大,建树时反向排序即可 1 #include

【BZOJ4942】[Noi2017]整数 线段树+DFS(卡过)

[BZOJ4942][Noi2017]整数 题目描述去uoj 题解:如果只有加法,那么直接暴力即可...(因为1的数量最多nlogn个) 先考虑加法,比较显然的做法就是将A二进制分解成log位,然后依次更新这log位,如果最高位依然有进位,那么找到最高位后面的第一个0,将中间的所有1变成0,那个0变成1.这个显然要用到线段树,但是复杂度是nlog2n的,肯定过不去. 于是我在考场上yy了一下,这log位是连续的,我们每次都要花费log的时间去修改一个岂不是很浪费?我们可以先在线段树上找到这段区间