hdu4348 - To the moon 可持久化线段树 区间修改 离线处理

法一:暴力!

让干什么就干什么,那么久需要可持久化线段树了。

但是空间好紧。怎么破?

不down标记好了!

每个点维护sum和add两个信息,sum是这段真实的和,add是这段整体加了多少,如果这段区间被完全包含,返回sum,否则加上add * 询问落在这段区间的长度再递归回答。

怎么还是MLE?

麻辣鸡指针好像8字节,所以改成数组的就过了。。。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>

using namespace std;

template<typename Q> Q &read(Q &x) {
    static char c, f;
    for(f = 0; c = getchar(), !isdigit(c); ) if(c == ‘-‘) f = 1;
    for(x = 0; isdigit(c); c = getchar()) x = x * 10 + c - ‘0‘;
    if(f) x = -x; return x;
}
template<typename Q> Q read() {
    static Q x; read(x); return x;
}

typedef long long LL;
const int N = 100000 + 10;
struct Node *pis;
struct Node {
    LL sum, add;
    Node *ch[2];

    Node *modify(int l, int r, int L, int R, LL d) {
        Node *o = new Node(*this);
        if(L <= l && r <= R) {
            o->add += d;
            o->sum += (r - l + 1) * d;
            return o;
        }
        int mid = (l + r) >> 1;
        if(L <= mid) o->ch[0] = ch[0]->modify(l, mid, L, R, d);
        if(mid < R) o->ch[1] = ch[1]->modify(mid + 1, r, L, R, d);
        o->sum = o->ch[0]->sum + o->ch[1]->sum + o->add * (r - l + 1);
        return o;
    }

    LL query(int l, int r, int L, int R) {
        if(L <= l && r <= R) return sum;
        int mid = (l + r) >> 1;
        LL res = (min(R, r) - max(L, l) + 1) * add;
        if(L <= mid) res += ch[0]->query(l, mid, L, R);
        if(mid < R) res += ch[1]->query(mid + 1, r, L, R);
        return res;
    }

    void *operator new(size_t) {
        return pis++;
    }
}pool[1000000 + 10], *root[N];

void build(Node *&o, int l, int r) {
    o = new Node, o->add = 0;
    if(l == r) return read(o->sum), void();
    int mid = (l + r) >> 1;
    build(o->ch[0], l, mid);
    build(o->ch[1], mid + 1, r);
    o->sum = o->ch[0]->sum + o->ch[1]->sum;
}

int main() {
#ifdef DEBUG
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif

    int n, m, cur;
    char opt[10];
    while(scanf("%d%d", &n, &m) == 2) {
        cur = 0, pis = pool;
        build(root[cur], 1, n);
        while(m--) {
            if(m == 1) {
                int debug = 1;
            }
            scanf("%s", opt);
            if(opt[0] == ‘C‘) {
                int l, r; LL d;
                read(l), read(r), read(d);
                root[cur + 1] = root[cur]->modify(1, n, l, r, d);
                cur++;
            }else if(opt[0] == ‘Q‘) {
                int l, r; read(l), read(r);
                printf("%I64d\n", root[cur]->query(1, n, l, r));
            }else if(opt[0] == ‘H‘) {
                int l, r, t; read(l), read(r), read(t);
                printf("%I64d\n", root[t]->query(1, n, l, r));
            }else read(cur);
        }
        puts("");
    }

    return 0;
}

指针版

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<iostream>
 6
 7 using namespace std;
 8
 9 template<typename Q> Q &read(Q &x) {
10     static char c, f;
11     for(f = 0; c = getchar(), !isdigit(c); ) if(c == ‘-‘) f = 1;
12     for(x = 0; isdigit(c); c = getchar()) x = x * 10 + c - ‘0‘;
13     if(f) x = -x; return x;
14 }
15 template<typename Q> Q read() {
16     static Q x; read(x); return x;
17 }
18
19 typedef long long LL;
20 const int N = 4000000 + 10;
21
22 int ch[N][2], tot, root[N];
23 LL sum[N], add[N];
24
25 int modify(int s, int l, int r, int L, int R, LL d) {
26     int x = tot++;
27     sum[x] = sum[s];
28     add[x] = add[s];
29     ch[x][0] = ch[s][0];
30     ch[x][1] = ch[s][1];
31
32     if(L <= l && r <= R) {
33         add[x] += d;
34         sum[x] += (r - l + 1) * d;
35     }else {
36         int mid = (l + r) >> 1;
37         if(L <= mid) ch[x][0] = modify(ch[s][0], l, mid, L, R, d);
38         if(mid < R) ch[x][1] = modify(ch[s][1], mid + 1, r, L, R, d);
39         sum[x] = sum[ch[x][0]] + sum[ch[x][1]] + add[x] * (r - l + 1);
40     }
41     return x;
42 }
43
44 LL query(int s, int l, int r, int L, int R) {
45     if(L <= l && r <= R) return sum[s];
46     int mid = (l + r) >> 1;
47     LL res = (min(R, r) - max(L, l) + 1) * add[s];
48     if(L <= mid) res += query(ch[s][0], l, mid, L, R);
49     if(mid < R) res += query(ch[s][1], mid + 1, r, L, R);
50     return res;
51 }
52
53 void build(int &s, int l, int r) {
54     s = tot++, add[s] = 0;
55     if(l == r) return read(sum[s]), void();
56     int mid = (l + r) >> 1;
57     build(ch[s][0], l, mid);
58     build(ch[s][1], mid + 1, r);
59     sum[s] = sum[ch[s][0]] + sum[ch[s][1]];
60 }
61
62 int main() {
63 #ifdef DEBUG
64     freopen("in.txt", "r", stdin);
65     freopen("out.txt", "w", stdout);
66 #endif
67
68     int n, m, cur;
69     char opt[10];
70     while(scanf("%d%d", &n, &m) == 2) {
71         cur = tot = 0;
72         build(root[cur], 1, n);
73         while(m--) {
74             if(m == 1) {
75                 int debug = 1;
76             }
77             scanf("%s", opt);
78             if(opt[0] == ‘C‘) {
79                 int l, r; LL d;
80                 read(l), read(r), read(d);
81                 root[cur + 1] = modify(root[cur], 1, n, l, r, d);
82                 cur++;
83             }else if(opt[0] == ‘Q‘) {
84                 int l, r; read(l), read(r);
85                 printf("%I64d\n", query(root[cur], 1, n, l, r));
86             }else if(opt[0] == ‘H‘) {
87                 int l, r, t; read(l), read(r), read(t);
88                 printf("%I64d\n", query(root[t], 1, n, l, r));
89             }else read(cur);
90         }
91 //        puts("");
92     }
93
94     return 0;
95 }

数组版

法二:离线!

主要需要处理H操作。

在第一遍读入数据的时候维护一个pos[]数组,表示当前第i个版本是由pos[i]这个C操作创建的。

然后碰到H就把它挂在pos[t]上就可以,第二遍处理的时候直接回答。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<algorithm>
  5 #include<iostream>
  6
  7 using namespace std;
  8
  9 template<typename Q> Q &read(Q &x) {
 10     static char c, f;
 11     for(f = 0; c = getchar(), !isdigit(c); ) if(c == ‘-‘) f = 1;
 12     for(x = 0; isdigit(c); c = getchar()) x = x * 10 + c - ‘0‘;
 13     if(f) x = -x; return x;
 14 }
 15 template<typename Q> Q read() {
 16     static Q x; read(x); return x;
 17 }
 18
 19 typedef long long LL;
 20 const int N = 100000 + 10;
 21
 22 int n, m;
 23 class SegementTree {
 24     private:
 25     LL sum[N * 4], tag[N * 4];
 26
 27     #define mid ((l + r) >> 1)
 28     #define ls s << 1, l, mid
 29     #define rs s << 1 | 1, mid + 1, r
 30
 31     void add_tag(int s, int l, int r, LL d) {
 32         tag[s] += d;
 33         sum[s] += (r - l + 1) * d;
 34     }
 35
 36     void down(int s, int l, int r) {
 37         if(tag[s]) {
 38             add_tag(ls, tag[s]);
 39             add_tag(rs, tag[s]);
 40             tag[s] = 0;
 41         }
 42     }
 43
 44     int lft, rgt;
 45     LL w;
 46
 47     void modify(int s, int l, int r) {
 48         if(lft <= l && r <= rgt) return add_tag(s, l, r, w);
 49         down(s, l, r);
 50         if(lft <= mid) modify(ls);
 51         if(mid < rgt) modify(rs);
 52         sum[s] = sum[s << 1] + sum[s << 1 | 1];
 53     }
 54
 55     LL query(int s, int l, int r) {
 56         if(lft <= l && r <= rgt) return sum[s];
 57         down(s, l, r);
 58         if(rgt <= mid) return query(ls);
 59         if(mid < lft) return query(rs);
 60         return query(ls) + query(rs);
 61     }
 62
 63     public:
 64     void build(int s, int l, int r) {
 65         tag[s] = 0;
 66         if(l == r) return read(sum[s]), void();
 67         build(ls), build(rs);
 68         sum[s] = sum[s << 1] + sum[s << 1 | 1];
 69     }
 70     #undef mid
 71     #undef ls
 72     #undef rs
 73
 74     void Modify(int l, int r, LL w) {
 75         lft = l, rgt = r, this->w = w;
 76         modify(1, 1, n);
 77     }
 78     LL Query(int l, int r) {
 79         lft = l, rgt = r;
 80         return query(1, 1, n);
 81     }
 82 }seg;
 83
 84 struct operation {
 85     char tp;
 86     int l, r;
 87     LL d;
 88 }opt[N];
 89
 90 #include<stack>
 91 stack<int> stk;
 92
 93 #include<vector>
 94 vector<int> G[N];
 95
 96 int pos[N];
 97 LL ans[N];
 98
 99 int main() {
100 #ifdef DEBUG
101     freopen("in.txt", "r", stdin);
102     freopen("out.txt", "w", stdout);
103 #endif
104
105     char s[10];
106     while(scanf("%d%d", &n, &m) == 2) {
107         seg.build(1, 1, n);
108         int cur = 0;
109         for(int i = 0; i < m; i++) {
110             scanf("%s", s);
111             opt[i].tp = s[0];
112             if(s[0] == ‘C‘) {
113                 read(opt[i].l), read(opt[i].r), read(opt[i].d);
114                 pos[++cur] = i;
115             }else if(s[0] == ‘Q‘) {
116                 read(opt[i].l), read(opt[i].r);
117             }else if(s[0] == ‘H‘) {
118                 read(opt[i].l), read(opt[i].r), read(opt[i].d);
119                 if(!opt[i].d) ans[i] = seg.Query(opt[i].l, opt[i].r);
120                 else G[pos[opt[i].d]].push_back(i);
121             }else cur = read(opt[i].d);
122         }
123
124         cur = 0;
125         for(int i = 0; i < m; i++) {
126             if(opt[i].tp == ‘C‘) {
127                 seg.Modify(opt[i].l, opt[i].r, opt[i].d);
128                 for(unsigned j = 0; j < G[i].size(); j++) {
129                     int k = G[i][j];
130                     ans[k] = seg.Query(opt[k].l, opt[k].r);
131                 }
132                 ++cur;
133                 stk.push(i);
134             }else if(opt[i].tp == ‘Q‘) {
135                 ans[i] = seg.Query(opt[i].l, opt[i].r);
136             }else if(opt[i].tp == ‘B‘) {
137                 while(cur > opt[i].d) {
138                     int k = stk.top(); stk.pop();
139                     seg.Modify(opt[k].l, opt[k].r, -opt[k].d);
140                     cur--;
141                 }
142             }
143         }
144
145         for(int i = 0; i < m; i++) {
146             if(opt[i].tp == ‘Q‘ || opt[i].tp == ‘H‘) {
147                 printf("%I64d\n", ans[i]);
148             }
149         }
150     }
151
152     return 0;
153 }

离线版

时间: 2024-12-17 22:10:56

hdu4348 - To the moon 可持久化线段树 区间修改 离线处理的相关文章

poj 2777 Count Color(线段树区间修改)

题目链接:http://poj.org/problem?id=2777 题目意思:就是问你在询问的区间里有几种不同的颜色 思路:这题和一般的区间修改差不多,但是唯一不同的就是我们要怎么计算有种颜色,所以这时候我们就需要把延时标记赋予不同的意义,当某段区间有多种颜色时就赋值为-1,当为一种颜色时就把它赋值为这个颜色的号数.这儿我们要怎么统计询问区间不同的颜色数叻,为了不重复计算同一种颜色,那么我们就需要用一个数组来标记计算过的颜色,当我们下次遇到时就不需要再次计算了.... 代码核心处就在计数那儿

hdu-5023 A Corrupt Mayor&#39;s Performance Art (线段树区间修改)

今天集训队打比赛的一道题,很明显是个线段树,我们队照着lrj蓝书敲了一通,机智的将修改值和加和改成了位运算:|= 但是好像哪里出了点小问题,就是不对,赛后又水了一遍,竟然过了...发现还是lrj的书好啊,市面上的模板一点也不好用,连区间修改都没有 . 等集训完了要静心好好系统的学习一下线段树 . 多看多刷lrj的书 . 细节参见代码: #include<bits/stdc++.h> using namespace std; const int maxn = 1000000 + 5; int n

【线段树区间修改】fzu2105Digits Count

/* 题意: 给出数组A,有以下几个操作: 1: AND(opn, L, R):把区间[L, R]中的元素A[i]改为A[i] & opn;;;;;; 2: OR(opn, L, R) :把区间[L, R]中的元素A[i]改为A[i] | opn;;;;;;; 3: XOR(opn, L, R):把区间[L, R]中的元素A[i]改为A[i] ^ opn;;;;;;; 4: SUM(L, R) :对区间[L, R]中的元素求和:::: ------------------------------

Wikilo 1191线段树区间修改单点查询

这题也算比较容易的了. 如果哪个区间已经没有黑色的话,就不用update了,就是因为这个原因WA了2发,唉-- #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <queue> #include <string> #incl

线段树区间修改模板

本来打算把大白书第三章一口气攻下来的,但是这个线段树也是卡了好久. 不敢过题太快,怕自己走马观花到头来结果什么都不会. 可也不能再拖了,在做题中也许有更多的体会. 模板一:1 L R v 表示区间[L, R]所有元素都加上v2 L R   表示查询区间[L, R]的sum, min, maxsumv[o]的定义为:如果只执行节点o及其子孙节点的中的add操作,节点o对应区间中所有数之和 1 //线段树区间修改 2 //1 L R v 表示区间[L, R]所有元素都加上v 3 //2 L R 表示

HDU - 1698 Just a Hook (线段树区间修改)

Description In the game of DotA, Pudge's meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive metallic sticks which are of the same length. Now Pudge wants to do some operations on the hook.

线段树区间修改 P3372 【模板】线段树 1

题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k 操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和 输出格式: 输出包含若干行整

UVA11992 - Fast Matrix Operations ( 线段树 + 区间修改 + 好题 )

UVA11992 - Fast Matrix Operations ( 线段树 + 区间修改 + 好题 ) 这是大白书上的例题,一直放着没有去A掉,这是一道线段树区间修改的好题. 线段树中需要维护三个域 ,max, min, sum,也就是区间最大值,最小值,区间和 题目大意: r 行 c 列 的全0矩阵,支持三个操作 1 x1 y1 x2 y2 v 子矩阵(x1,y1,x2,y2)的所有元素增加v 2 x1 y1 x2 y2 v 子矩阵(x1,y1,x2,y2)的所有元素设为v 3 x1 y1

hdu 4902 Nice boat(线段树区间修改,输出最终序列)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4902 Problem Description There is an old country and the king fell in love with a devil. The devil always asks the king to do some crazy things. Although the king used to be wise and beloved by his peopl