HDU - 4348 [月へ]スタンダード・オンライン会長ツリー
https://cn.vjudge.net/contest/304073#problem/G
問題の意味
mおよびnは数所定の操作は、時間が0で開始し、動作は、4つのカテゴリーに分けられます:
ノードの問い合わせ[X、Y]と現在の時間間隔 - QのXY
CのXYZ - [X、Y]ここで、すべてのセクションプラスZの数、現在時刻+ 1つのノード
H XYZ - 時間間隔とノードに問い合わせ[X、Y]のz
B X - Xノードは、現在の時間となります
分析
いくつかの質問彼らは「右の値のセグメントツリー」(木の各ノードは、保存された値に属さなかったの前に\(合計\)はラベルで各番号を表す現在の数の数を表します)、離散のためので、必要性、 。
ツリーの各ノードは価値構築する必要があり、この問題の存在\(合計\)は、従来のセグメントツリーで、間隔と(リクエストとの間隔に関するトピック理由)の本当の意味です。
更新間隔については、我々は怠惰な配列を使用することができます。再帰下降時から、我々はこの親ノード、直接更新を合計することができます。与えられたクエリ間隔に直面し、間隔がちょうど完全に一致した場合、我々は怠惰更新する必要があります。そうすることで、複雑な操作のプッシュダウンを保存することができます。
照会すると、我々はすべての間隔は怠け者プラスされている見つける必要があります。
特定の操作のコードを参照してください。
コード
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <bitset>
#include <cctype>
#include <cstdio>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 5;
int n, m, cnt;
ll a[maxn];
int root[maxn];
struct node {
int l, r;
ll sum, lazy;
}T[maxn*40];
void init() {
cnt = 0;
}
void build(int l, int r, int &rt) {
rt = ++ cnt;
T[rt].l = l;
T[rt].r = r;
T[rt].sum = a[l];
T[rt].lazy = 0;
if(l == r) {
return ;
}
int mid = (l+r) / 2;
build(l, mid, T[rt].l);
build(mid+1, r, T[rt].r);
T[rt].sum = T[T[rt].l].sum + T[T[rt].r].sum;
}
void update(int L, int R, int l, int r, int &x, int y, ll c) {
T[++cnt] = T[y];
T[cnt].sum += c*(R-L+1);// 把每个区间的增量都算上
x = cnt;
if(L == l && R == r) {
T[cnt].lazy += c; // 正好重合时更新lazy标记
return ;
}
int mid = (l+r) / 2;
// 区间更新
if(mid >= R) {
update(L, R, l, mid, T[x].l, T[y].l, c);
}
else if(mid < L) {
update(L, R, mid+1, r, T[x].r, T[y].r, c);
}
else {
update(L, mid, l, mid, T[x].l, T[y].l, c);
update(mid+1, R, mid+1, r, T[x].r, T[y].r, c);
}
}
ll query(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) {
return T[rt].sum;
}
ll ans = T[rt].lazy*(R-L+1); // 每个需要找的区间都得加
int mid = (l+r) / 2;
if(mid >= R) {
ans += query(L, R, l, mid, T[rt].l);
}
else if(mid < L) {
ans += query(L, R, mid+1, r, T[rt].r);
}
else {
ans += query(L, mid, l, mid, T[rt].l);
ans += query(mid+1, R, mid+1, r, T[rt].r);
}
return ans;
}
int main() {
while(~scanf("%d%d", &n, &m)) {
init();
for(int i = 1; i <= n; i++) {
scanf("%lld", &a[i]); // 非权值线段树,不需要离散化,存的是原数
}
build(1, n, root[0]);
// cout << T[1].sum << endl;
int now_time = 0;
for(int i = 1; i <= m; i++) {
char f[10];
int x, y, t;
ll c;
scanf("%s", f);
if(f[0] == 'Q') {
scanf("%d%d", &x, &y);
printf("%lld\n", query(x, y, 1, n, root[now_time]));
}
else if(f[0] == 'C') {
scanf("%d%d%lld", &x, &y, &c);
now_time ++;
update(x, y, 1, n, root[now_time], root[now_time-1], c);
}
else if(f[0] == 'H') {
scanf("%d%d%d", &x, &y, &t);
printf("%lld\n", query(x, y, 1, n, root[t]));
}
else {
scanf("%d", &t);
now_time = t;
}
}
}
return 0;
}