Weed

Time Limit: 20 Sec Memory Limit: 512 MB

Description

从前有个栈,一开始是空的。
  你写下了 m 个操作,每个操作形如 k v :
    若 k = 0,代表往栈顶加入一个数 v
    若 k = 1,则代表从栈顶弹出 v 个数,如果栈中的元素少于 v 个,则全部弹出。
  接着你又进行了 q 次修改,每次你会选择一个操作,并且修改它的两个参数。
  在每次修改后,你都要求出如果依次执行这些操作,最后栈中剩下的元素之和。

Input

第一行两个正整数 m,q,分别表示操作数和修改次数。
  接下来 m 行,每行两个整数 k,v,代表一个操作。
  接下来 q 行,每行三个正整数 c,k,v,表示将第 c 个操作的参数修改为 k 和 v。

Output

输出 q 行,每行一个整数,代表依次执行所有操作后栈中剩下的元素之和。

Sample Input

5 2
  0 3
  0 2
  0 3
  1 1
  0 5
  1 0 3
  1 0 1

Sample Output

10
  8

HINT

m,q ≤ 2×1e5, v ≤ 1e4

Solution

首先,我们可以把一个操作拆成:先删除若干个数,然后加入若干个数

那么我们可以用线段树来维护,一个节点记录:删除del个数加入add个数这add个数的和是val

那么我们只需要支持单点修改,答案显然就是Node[1].val。问题在于怎么合并两个节点的信息。

我们分情况讨论,记录左儿子为L,右儿子为R。显然信息形如:----+++ / -----+++。讨论一下 R.delL.add 的关系:

1. 显然当 L.add <= R.del 的时候, del 即为 L.del + R剩余的del ,add 即为 R.add,val 即为 R.val

2. 否则,当 L.add > R.del 的时候,难点在于 L 剩下多少 val,只要讨论出了这个问题,就解决了该题。

我们令函数 Query(i, k) 表示 删除节点 i后 k 个值,剩下的 val。那么显然这个也只要分类讨论即可:

1. k = R.add,返回 i.val - R.val 即可,比较显然;

2. k < R.add,显然我们需要继续往 R 递归,返回 i.val - R.val + Query(R, k)

3. k > R.add,显然我们需要往 L 递归,显然 k 先减去 R.add,又因为存在R.del这一段,所以 L 的后面几个被删除的,要多查几个,所以返回 Query(L, k - R.add + R.del)

然后我们写个线段树,就解决了这道题啦QWQ。

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
#include<bits/stdc++.h>
using namespace std;
typedef long long s64;

const int ONE = 1e6 + 5;

int m, T;

struct point
{
int opt, val;
}oper[ONE];

struct power
{
int add, del, val;
}Node[ONE * 4];

int get()
{
int res=1,Q=1;char c;
while( (c=getchar())<48 || c>57 )
if(c=='-')Q=-1;
res=c-48;
while( (c=getchar())>=48 && c<=57 )
res=res*10+c-48;
return res*Q;
}

int Query(int i, int k)
{
int L = i << 1, R = i << 1 | 1;
if(k == Node[R].add) return Node[i].val - Node[R].val;
if(k < Node[R].add) return Node[i].val - Node[R].val + Query(R, k);
if(k > Node[R].add) return Query(L, k - Node[R].add + Node[R].del);
}

power Merge(int L, int R)
{
power c = (power){0, 0, 0};
if(Node[L].add <= Node[R].del)
c.del = Node[L].del + Node[R].del - Node[L].add,
c.add = Node[R].add, c.val = Node[R].val;
if(Node[L].add > Node[R].del)
{
c.del = Node[L].del;
c.add = Node[L].add - Node[R].del + Node[R].add;
c.val = Query(L, Node[R].del) + Node[R].val;
}
return c;
}

void Build(int i, int l, int r)
{
if(l == r)
{
if(oper[l].opt == 0) Node[i] = (power){1, 0, oper[l].val};
else Node[i] = (power){0, oper[l].val, 0};
return;
}
int mid = l + r >> 1;
Build(i << 1, l, mid); Build(i << 1 | 1, mid + 1, r);
Node[i] = Merge(i << 1, i << 1 | 1);

}

void Update(int i, int l, int r, int L)
{
if(L <= l && r <= L)
{
if(oper[l].opt == 0) Node[i] = (power){1, 0, oper[l].val};
else Node[i] = (power){0, oper[l].val, 0};
return;
}
int mid = l + r >> 1;
if(L <= mid) Update(i << 1, l, mid, L);
else Update(i << 1 | 1, mid + 1, r, L);
Node[i] = Merge(i << 1, i << 1 | 1);
}

int main()
{
m = get(); T = get();
for(int i = 1; i <= m; i++)
oper[i].opt = get(), oper[i].val = get();
Build(1, 1, m);
while(T--)
{
int id = get();
oper[id].opt = get(); oper[id].val = get();
Update(1, 1, m, id);
printf("%d\n", Node[1].val);
}
}