0%

P13825 【模板】线段树 1.5(指针式动态开点线段树)

题目大意

P13825 【模板】线段树 1.5

题目描述

如题,已知一个长度为 nn

的数列 {ai}\{a_i\}1in1 \leq i \leq n),初始时 aa 序列满足 ai=ia_i = i。你需要进行下面两种操作:

  1. 将某区间每一个数加上 kk

  2. 求出某区间每一个数的和。

输入格式

第一行包含两个整数 n,mn, m,分别表示该数列数字的个数和操作的总个数。

接下来 mm 行每行包含 3344 个整数,表示一个操作,具体如下:

  1. 1 l r k:将区间 [l,r][l,r] 内每个数加上 kk

  2. 2 l r:输出区间 [l,r][l,r] 内每个数的和。

输出格式

输出包含若干行整数,即为所有操作 2 的结果。

输入输出样例 #1

输入 #1

1
2
3
4
5
6
5 5
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4

输出 #1

1
2
3
9
9
18

说明/提示

对于 30%30\% 的数据,n8n \le 8m10m \le 10

对于 50%50\% 的数据,n105n \le {10}^5

对于 100%100\% 的数据,1m,k1051 \le m,k \le {10}^51lrn1091 \leq l \leq r \leq n\leq 10^9

思路讲解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136

/*
* 2026-03-08 P13825 【模板】线段树 1.5 动态开点线段树
* AC https://www.luogu.com.cn/record/266006147
*
*/
struct Tag {
// 在母串中的这个位置
ll add=0;
bool need_apply=false;
void apply(const Tag &t) {
add+=t.add;
need_apply=true;
}
};

struct Info {
ll l=0,r=0;
i128 sum=0;
static Info merge(const Info &a,const Info &b) {
Info res=a;
res.r=b.r;
res.sum+=b.sum;
return res;
}
void apply(const Tag&t) {
if (!t.need_apply) {
return;
}
ll len=r-l+1;
sum+=len*t.add;
}
};

// 我认为还是用 C++14 的写法,把你要写的东西传进去比较好,不容易写错
template<class I=Info,class T=Tag>
struct SEG {
// 如果不需要泛型,可以用下面的来替代
// using I=Info;
// using T=Tag;
struct Node {
I info;
T tag;
Node* rs=nullptr;
Node* ls=nullptr;
};

void init_node(Node *u,ll l,ll r) {
u->info.l=l;
u->info.r=r;
u->info.sum=i128(u->info.l+u->info.r)*(u->info.r-u->info.l+1)/2;
}

Node* root=nullptr;
ll N;

static bool isIntersect(ll l1, ll r1, ll l2, ll r2) {
if (!(l1 > r2 || r1 < l2)) return true;
return false;
}

SEG(ll N):N(N) {
root=new Node();
root->info.l=1;
root->info.r=N;
init_node(root,1,N);
}

void extend(Node *u) {
if (u->ls==nullptr) {
u->ls=new Node();
init_node(u->ls,u->info.l,(u->info.l+u->info.r)>>1);
}
if (u->rs==nullptr) {
u->rs=new Node();
init_node(u->rs,((u->info.l+u->info.r)>>1)+1,u->info.r);
}
}

void push(Node *u) {
if (u->info.l==u->info.r) {
return;
}
extend(u);
if (u->tag.need_apply) {
u->ls->info.apply(u->tag);
u->rs->info.apply(u->tag);
u->ls->tag.apply(u->tag);
u->rs->tag.apply(u->tag);
u->tag={};
}
}
void pull(Node *u) {
if (u->info.l==u->info.r) {
return;
}
u->info=I::merge(u->ls->info,u->rs->info);
}
void modify(Node*u,ll l,ll r,const T& t) {
if (u->info.l>=l && u->info.r<=r) {
u->info.apply(t);
u->tag.apply(t);
return;
}
push(u);
if (isIntersect(u->ls->info.l,u->ls->info.r,l,r)) {
modify(u->ls,l,r,t);
}
if (isIntersect(u->rs->info.l,u->rs->info.r,l,r)) {
modify(u->rs,l,r,t);
}
pull(u);
}

Info query(Node *u,ll l,ll r) {
if (u->info.l>=l && u->info.r<=r) {
return u->info;
}
Info res;
bool is_get=false;
push(u);
if (isIntersect(u->ls->info.l,u->ls->info.r,l,r)) {
res=query(u->ls,l,r);
is_get=true;
}
if (isIntersect(u->rs->info.l,u->rs->info.r,l,r)) {
if (!is_get) {
res=query(u->rs,l,r);
}else {
res=I::merge(res,query(u->rs,l,r));
}
}
return res;
}
};

AC代码

AC
https://www.luogu.com.cn/record/266006147

心路历程(WA,TLE,MLE……)

不要忘记初始化这个根节点。

image