Radioactive 题解

  1. 1. Solution
    1. 1.1. 解题思路
    2. 1.2. 优化
    3. 1.3. 细节
      1. 1.3.1. 1
      2. 1.3.2. 2
      3. 1.3.3. 3
      4. 1.3.4. 4
    4. 1.4. Code

这道题还是很水的,做了三天才做出来

Solution

一看区间操作,就是线段树。

不过虽然说着简单,但是细节有很多,请注意这里讲到的每一个细节。

解题思路

观察下放操作,先是升序,再是降序。

若是直接下放,会出现很多复杂的情况,比如说,原来的序列被切分成 的情况。这样就要处理很多特殊情况。

经验告诉我们, 操作可以分解为一次上升,一次点修改,一次下降。

即:

变为 和剩下的 的操作。

单独操作,每一个下方操作都是单调的,没有特殊情况。

对于 ,我们保存两个 ,分别用来记录下放的上升和下降。

每一次分配 直接使用等差数列求和公式求和即可。最坏时间复杂度为

这里之所以说是 ,是因为每一次下放的操作都会遍历之前的所有 操作,肯定可以卡到 。况且空间复杂度为 。绝对需要优化。

优化

注意到就是 的下放导致时空爆掉,所以我们重点攻克 的下放和记录操作。

在一节数学课前,我找到了灵感:

等差数列有个不知道是不是定理的真命题,即两组长度相同的等差数列,每个数一一对应相加时,得到的等差数列,首项为两组等差数列的首项之和,末项也是末项之和,同样的,公差也是两公差之和。

至于证明,很简单嘛(

然后,我们就发现,每次 记录的长度都是固定的,即

所以,我们只需要记录并累加首项,末项和公差即可。

时间复杂度降为 (可能带点大系数,我不想优化了);空间复杂度降为

细节

1

有可能为负数,稍微加个数就好了

2

下放的时候一定要按照区间划分好的 来划分,否则有可能划错。

3

在下放时,只需要保留在 区间内的修改就好了。

第一行两个整数 ,表示你负责的区间在 ,共有 组事件发生。

不会有人没看到吧

4

就没啥了 ,都是我粗心错的小错误

Code

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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#include<bits/stdc++.h>
#define ll long long
#define gc getchar()
using namespace std;
template<typename T>
void read(T&r)
{
r=0;
char ch=gc,last='z';
while(!isdigit(ch)) last=ch,ch=gc;
while(isdigit(ch)) r=r*10+ch-'0',ch=gc;
if(last=='-') r=-r;
}

int num,root;
struct pNode{
ll l,r;
};

struct lNode{
ll l,r,k;
lNode operator + (lNode b)
{
this->l+=b.l;
this->r+=b.r;
this->k+=b.k;
return *this;
}
lNode operator += (lNode b)
{
*this=*this+b;
return *this;
}
};

struct Node{
int l,r;
int lc,rc;
ll data;
bool lazy,lazyl,lazyr;
ll laz;
lNode lazl,lazr;
}tree[8000001];
ll a[4000001];

void clazy(Node &n,Node &t)
{
n.laz+=t.laz;
n.data+=t.laz*(n.r-n.l+1);
n.lazy=true;
}

void lazyc(Node &t)
{
if(t.lc!=-1) clazy(tree[t.lc],t);
if(t.rc!=-1) clazy(tree[t.rc],t);
t.laz=t.lazy=0;
if(t.lazyl)
{
ll ql=tree[t.lc].r-tree[t.lc].l+1,qr=tree[t.rc].r-tree[t.rc].l+1;
tree[t.lc].data+=(t.lazl.l+(t.lazl.l+t.lazl.k*(ql-1)))*ql/2;
tree[t.lc].lazl+=((lNode){t.lazl.l,t.lazl.l+t.lazl.k*(ql-1),t.lazl.k});
tree[t.rc].data+=((t.lazl.l+t.lazl.k*ql)+t.lazl.r)*qr/2;
tree[t.rc].lazl+=((lNode){t.lazl.l+t.lazl.k*ql,t.lazl.r,t.lazl.k});
t.lazyl=false;
tree[t.lc].lazyl=true;
tree[t.rc].lazyl=true;
t.lazl={0,0,0};
}
if(t.lazyr)
{
ll ql=tree[t.lc].r-tree[t.lc].l+1,qr=tree[t.rc].r-tree[t.rc].l+1;
tree[t.lc].data+=(t.lazr.l+(t.lazr.l-t.lazr.k*(ql-1)))*ql/2;
tree[t.lc].lazr+=((lNode){t.lazr.l,(t.lazr.l-t.lazr.k*(ql-1)),t.lazr.k});
tree[t.rc].data+=((t.lazr.l-t.lazr.k*ql)+t.lazr.r)*qr/2;
tree[t.rc].lazr+=((lNode){t.lazr.l-t.lazr.k*ql,t.lazr.r,t.lazr.k});
t.lazyr=false;
tree[t.lc].lazyr=true;
tree[t.rc].lazyr=true;
t.lazr={0,0,0};
}
}

int bt(int l,int r)
{
int p=++num;Node &t=tree[p];
t.l=l;
t.r=r;
t.lc=t.rc=-1;
t.laz=t.lazy=0;
if(l==r) t.data=a[l];
else
{
int mid=(l+r)/2;
t.lc=bt(l,mid);
t.rc=bt(mid+1,r);
t.data=tree[t.lc].data+tree[t.rc].data;
}
return p;
}

void change(Node &t,int l,int r,ll data)
{
if(t.l==l&&t.r==r) t.data+=data*(r-l+1),t.lazy=true,t.laz+=data;
else
{
int mid=(t.l+t.r)/2;
if(t.lazy||t.lazyl||t.lazyr)
lazyc(t);
if(r<=mid) change(tree[t.lc],l,r,data);
else if(mid<l) change(tree[t.rc],l,r,data);
else
{
change(tree[t.lc],l,mid,data);
change(tree[t.rc],mid+1,r,data);
}
t.data=tree[t.lc].data+tree[t.rc].data;
}
}

void change_dl(Node &t,int l,int r,ll datal,ll datar)
{
if(t.l==l&&t.r==r) t.data+=(datal+datar)*(datar-datal+1)/2,t.lazyl=true,t.lazl+=((lNode){datal,datar,1});
else
{
int mid=(t.l+t.r)/2;
if(t.lazy||t.lazyl||t.lazyr)
lazyc(t);
if(r<=mid) change_dl(tree[t.lc],l,r,datal,datar);
else if(mid<l) change_dl(tree[t.rc],l,r,datal,datar);
else
{
int ql=mid-l+1;
change_dl(tree[t.lc],l,mid,datal,(datal+ql-1));
change_dl(tree[t.rc],mid+1,r,(datal+ql),datar);
}
t.data=tree[t.lc].data+tree[t.rc].data;
}
}

void change_dr(Node &t,int l,int r,ll datal,ll datar)
{
if(t.l==l&&t.r==r) t.data+=(datal+datar)*(datal-datar+1)/2,t.lazyr=true,t.lazr+=((lNode){datal,datar,1});
else
{
int mid=(t.l+t.r)/2;
if(t.lazy||t.lazyl||t.lazyr)
lazyc(t);
if(r<=mid) change_dr(tree[t.lc],l,r,datal,datar);
else if(mid<l) change_dr(tree[t.rc],l,r,datal,datar);
else
{
int ql=mid-l+1;
change_dr(tree[t.lc],l,mid,datal,(datal-ql+1));
change_dr(tree[t.rc],mid+1,r,(datal-ql),datar);
}
t.data=tree[t.lc].data+tree[t.rc].data;
}
}

int aa,b,m;
ll z;
void change_hd(Node &t,ll l,ll r,int x,ll data) //?????,[l,x-1],[x,x],[x+1,r]
{
change(t,x,x,data);
if(max(l,1ll)<=x-1) change_dl(t,max(l,1ll),x-1,max(1ll,2-l),data-1);
if(x+1<=min(r,b+z)) change_dr(t,x+1,min(r,b+z),data-1,max(1ll,1+(r-(b+z))));
t.data=tree[t.lc].data+tree[t.rc].data;
}

ll find(Node &t,int l,int r)
{
if(t.l==l&&t.r==r) return t.data;
int mid=(t.l+t.r)/2;
if(t.lazy||t.lazyl||t.lazyr)
lazyc(t);
if(r<=mid) return find(tree[t.lc],l,r);
if(mid<l) return find(tree[t.rc],l,r);
return find(tree[t.lc],l,mid)+find(tree[t.rc],mid+1,r);
}

int main(int argc,char *argv[])
{
read(aa),read(b),read(m);z=(1-aa);
for(int i=1;i<=b+z;i++) read(a[i]),a[i]=-a[i];
root=bt(1,b+z);
ll x,y;ll k;
while(m--)
{
char ch='0';
while(ch<'1'||ch>'2') ch=char(getchar());
read(x);
if(ch=='1')
{
read(k);
change_hd(tree[root],x-k+z+1,x+k+z-1,x+z,k);
}
if(ch=='2')
{
read(y);
if(x>y) swap(x,y);
printf("%lld\n",-find(tree[root],x+z,y+z));
}
}
return 0;
}

完结撒花qwq