法一:暴力!

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

但是空间好紧。怎么破?

不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 = ; c = getchar(), !isdigit(c); ) if(c == '-') f = ;
for(x = ; isdigit(c); c = getchar()) x = x * + c - '';
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 = + ;
struct Node *pis;
struct Node {
LL sum, add;
Node *ch[]; 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 + ) * d;
return o;
}
int mid = (l + r) >> ;
if(L <= mid) o->ch[] = ch[]->modify(l, mid, L, R, d);
if(mid < R) o->ch[] = ch[]->modify(mid + , r, L, R, d);
o->sum = o->ch[]->sum + o->ch[]->sum + o->add * (r - l + );
return o;
} LL query(int l, int r, int L, int R) {
if(L <= l && r <= R) return sum;
int mid = (l + r) >> ;
LL res = (min(R, r) - max(L, l) + ) * add;
if(L <= mid) res += ch[]->query(l, mid, L, R);
if(mid < R) res += ch[]->query(mid + , r, L, R);
return res;
} void *operator new(size_t) {
return pis++;
}
}pool[ + ], *root[N]; void build(Node *&o, int l, int r) {
o = new Node, o->add = ;
if(l == r) return read(o->sum), void();
int mid = (l + r) >> ;
build(o->ch[], l, mid);
build(o->ch[], mid + , r);
o->sum = o->ch[]->sum + o->ch[]->sum;
} int main() {
#ifdef DEBUG
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif int n, m, cur;
char opt[];
while(scanf("%d%d", &n, &m) == ) {
cur = , pis = pool;
build(root[cur], , n);
while(m--) {
if(m == ) {
int debug = ;
}
scanf("%s", opt);
if(opt[] == 'C') {
int l, r; LL d;
read(l), read(r), read(d);
root[cur + ] = root[cur]->modify(, n, l, r, d);
cur++;
}else if(opt[] == 'Q') {
int l, r; read(l), read(r);
printf("%I64d\n", root[cur]->query(, n, l, r));
}else if(opt[] == 'H') {
int l, r, t; read(l), read(r), read(t);
printf("%I64d\n", root[t]->query(, n, l, r));
}else read(cur);
}
puts("");
} return ;
}

指针版

 #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 = ; c = getchar(), !isdigit(c); ) if(c == '-') f = ;
for(x = ; isdigit(c); c = getchar()) x = x * + c - '';
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 = + ; int ch[N][], tot, root[N];
LL sum[N], add[N]; int modify(int s, int l, int r, int L, int R, LL d) {
int x = tot++;
sum[x] = sum[s];
add[x] = add[s];
ch[x][] = ch[s][];
ch[x][] = ch[s][]; if(L <= l && r <= R) {
add[x] += d;
sum[x] += (r - l + ) * d;
}else {
int mid = (l + r) >> ;
if(L <= mid) ch[x][] = modify(ch[s][], l, mid, L, R, d);
if(mid < R) ch[x][] = modify(ch[s][], mid + , r, L, R, d);
sum[x] = sum[ch[x][]] + sum[ch[x][]] + add[x] * (r - l + );
}
return x;
} LL query(int s, int l, int r, int L, int R) {
if(L <= l && r <= R) return sum[s];
int mid = (l + r) >> ;
LL res = (min(R, r) - max(L, l) + ) * add[s];
if(L <= mid) res += query(ch[s][], l, mid, L, R);
if(mid < R) res += query(ch[s][], mid + , r, L, R);
return res;
} void build(int &s, int l, int r) {
s = tot++, add[s] = ;
if(l == r) return read(sum[s]), void();
int mid = (l + r) >> ;
build(ch[s][], l, mid);
build(ch[s][], mid + , r);
sum[s] = sum[ch[s][]] + sum[ch[s][]];
} int main() {
#ifdef DEBUG
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif int n, m, cur;
char opt[];
while(scanf("%d%d", &n, &m) == ) {
cur = tot = ;
build(root[cur], , n);
while(m--) {
if(m == ) {
int debug = ;
}
scanf("%s", opt);
if(opt[] == 'C') {
int l, r; LL d;
read(l), read(r), read(d);
root[cur + ] = modify(root[cur], , n, l, r, d);
cur++;
}else if(opt[] == 'Q') {
int l, r; read(l), read(r);
printf("%I64d\n", query(root[cur], , n, l, r));
}else if(opt[] == 'H') {
int l, r, t; read(l), read(r), read(t);
printf("%I64d\n", query(root[t], , n, l, r));
}else read(cur);
}
// puts("");
} return ;
}

数组版

法二:离线!

主要需要处理H操作。

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

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

 #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 = ; c = getchar(), !isdigit(c); ) if(c == '-') f = ;
for(x = ; isdigit(c); c = getchar()) x = x * + c - '';
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 = + ; int n, m;
class SegementTree {
private:
LL sum[N * ], tag[N * ]; #define mid ((l + r) >> 1)
#define ls s << 1, l, mid
#define rs s << 1 | 1, mid + 1, r void add_tag(int s, int l, int r, LL d) {
tag[s] += d;
sum[s] += (r - l + ) * d;
} void down(int s, int l, int r) {
if(tag[s]) {
add_tag(ls, tag[s]);
add_tag(rs, tag[s]);
tag[s] = ;
}
} int lft, rgt;
LL w; void modify(int s, int l, int r) {
if(lft <= l && r <= rgt) return add_tag(s, l, r, w);
down(s, l, r);
if(lft <= mid) modify(ls);
if(mid < rgt) modify(rs);
sum[s] = sum[s << ] + sum[s << | ];
} LL query(int s, int l, int r) {
if(lft <= l && r <= rgt) return sum[s];
down(s, l, r);
if(rgt <= mid) return query(ls);
if(mid < lft) return query(rs);
return query(ls) + query(rs);
} public:
void build(int s, int l, int r) {
tag[s] = ;
if(l == r) return read(sum[s]), void();
build(ls), build(rs);
sum[s] = sum[s << ] + sum[s << | ];
}
#undef mid
#undef ls
#undef rs void Modify(int l, int r, LL w) {
lft = l, rgt = r, this->w = w;
modify(, , n);
}
LL Query(int l, int r) {
lft = l, rgt = r;
return query(, , n);
}
}seg; struct operation {
char tp;
int l, r;
LL d;
}opt[N]; #include<stack>
stack<int> stk; #include<vector>
vector<int> G[N]; int pos[N];
LL ans[N]; int main() {
#ifdef DEBUG
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif char s[];
while(scanf("%d%d", &n, &m) == ) {
seg.build(, , n);
int cur = ;
for(int i = ; i < m; i++) {
scanf("%s", s);
opt[i].tp = s[];
if(s[] == 'C') {
read(opt[i].l), read(opt[i].r), read(opt[i].d);
pos[++cur] = i;
}else if(s[] == 'Q') {
read(opt[i].l), read(opt[i].r);
}else if(s[] == 'H') {
read(opt[i].l), read(opt[i].r), read(opt[i].d);
if(!opt[i].d) ans[i] = seg.Query(opt[i].l, opt[i].r);
else G[pos[opt[i].d]].push_back(i);
}else cur = read(opt[i].d);
} cur = ;
for(int i = ; i < m; i++) {
if(opt[i].tp == 'C') {
seg.Modify(opt[i].l, opt[i].r, opt[i].d);
for(unsigned j = ; j < G[i].size(); j++) {
int k = G[i][j];
ans[k] = seg.Query(opt[k].l, opt[k].r);
}
++cur;
stk.push(i);
}else if(opt[i].tp == 'Q') {
ans[i] = seg.Query(opt[i].l, opt[i].r);
}else if(opt[i].tp == 'B') {
while(cur > opt[i].d) {
int k = stk.top(); stk.pop();
seg.Modify(opt[k].l, opt[k].r, -opt[k].d);
cur--;
}
}
} for(int i = ; i < m; i++) {
if(opt[i].tp == 'Q' || opt[i].tp == 'H') {
printf("%I64d\n", ans[i]);
}
}
} return ;
}

离线版

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

  1. HDU 4348.To the moon SPOJ - TTM To the moon -可持久化线段树(带修改在线区间更新(增减)、区间求和、查询历史版本、回退到历史版本、延时标记不下放(空间优化))

    To the moon Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total ...

  2. hdu4348 To the moon (可持久化线段树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4348 题目大意:给定含有n个数的序列,有以下四种操作 1.C l r d:表示对区间[l,r]中的数加 ...

  3. 计蒜客 38229.Distance on the tree-1.树链剖分(边权)+可持久化线段树(区间小于等于k的数的个数)+离散化+离线处理 or 2.树上第k大(主席树)+二分+离散化+在线查询 (The Preliminary Contest for ICPC China Nanchang National Invitational 南昌邀请赛网络赛)

    Distance on the tree DSM(Data Structure Master) once learned about tree when he was preparing for NO ...

  4. 【bzoj2653】middle 可持久化线段树区间合并

    题目描述 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[ ...

  5. Codeforces Round #442 (Div. 2) E Danil and a Part-time Job (dfs序加上一个线段树区间修改查询)

    题意: 给出一个具有N个点的树,现在给出两种操作: 1.get x,表示询问以x作为根的子树中,1的个数. 2.pow x,表示将以x作为根的子树全部翻转(0变1,1变0). 思路:dfs序加上一个线 ...

  6. 题解报告:hdu 1698 Just a Hook(线段树区间修改+lazy懒标记的运用)

    Problem Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing for m ...

  7. poj 2528 线段树区间修改+离散化

    Mayor's posters POJ 2528 传送门 线段树区间修改加离散化 #include <cstdio> #include <iostream> #include ...

  8. HDU 4348 To the moon 可持久化线段树,有时间戳的区间更新,区间求和

    To the moonTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/contest/view.a ...

  9. HDU 4417.Super Mario-可持久化线段树(无修改区间小于等于H的数的个数)

    Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

随机推荐

  1. C++学习笔记-1-自增和自减运算符

    1. post-increment and pre-increment 的区别 来源:http://www.c4learn.com/c-programming/c-increment-operator ...

  2. PHP 内存不足

    今天编写数据库备份类时,在运行的过程中,出现了内存不足的问题,提示:Fatal error: Allowed memory size of 25165824 bytes exhausted (trie ...

  3. MySQL设置

    在MySQL的使用中很容易出现乱码的情况. 实际上在MySQL中有个地方表明了系统中所用到的所有的字符集. 例如: 从中可以看出,对于server和database的默认字符集都是latin1,这样很 ...

  4. demo_03HTML5中的动画效果

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  5. ThinkPHP HTML标签代码和UBB互相转换

    1.UBB 转为 HTML TP的扩展里面自带一个ubb方法,用这个方法就能把用户输入的ubb格式代码转换为HTML标签的代码.这里用到的基本知识就是正则表达式啦,今天先不讲正则表达式. 来看一下TP ...

  6. php生成图片验证码

    验证码主要用来防止暴力破解的方式来进行登录,下面是php中的图片验证码生成方式,废话不多说,直接上代码 /** * 生成验证码 */ function buildRandomString($type= ...

  7. JSON字符串序列化与反序列化浅试

    一.添加引用(using Newtonsoft.Json.Linq;) 二. 1.生成json字符串源码 List<string> list = new List<string> ...

  8. 关于PowerDesigner

    1. PowerDesigner将所有的小写改为大写:Tools->Model Option->左侧菜单中“Naming conversion”->Column->Code – ...

  9. Eclipse插件卸载

            以前搞过安卓,重装系统后,安卓损坏了,每次还会提示那个窗口很烦人.       使用Eclipse自带的卸载插件功能即可,Help->About Eclipse->Inst ...

  10. 关于 width;height

    IE Firefox Chrome Safari window(width|height)   no yes yes document.body document.documentElement 网页 ...