Weed
Time Limit: 20 Sec Memory Limit: 512 MBDescription
从前有个栈,一开始是空的。
你写下了 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.del 与 L.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 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstdio> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cmath> 8 #include<vector> 9 using namespace std; 10 typedef long long s64; 11 12 const int ONE = 1e6 + 5; 13 14 int m, T; 15 16 struct point 17 { 18 int opt, val; 19 }oper[ONE]; 20 21 struct power 22 { 23 int add, del, val; 24 }Node[ONE * 4]; 25 26 int get() 27 { 28 int res=1,Q=1;char c; 29 while( (c=getchar())<48 || c>57 ) 30 if(c=='-')Q=-1; 31 res=c-48; 32 while( (c=getchar())>=48 && c<=57 ) 33 res=res*10+c-48; 34 return res*Q; 35 } 36 37 int Query(int i, int k) 38 { 39 int L = i << 1, R = i << 1 | 1; 40 if(k == Node[R].add) return Node[i].val - Node[R].val; 41 if(k < Node[R].add) return Node[i].val - Node[R].val + Query(R, k); 42 if(k > Node[R].add) return Query(L, k - Node[R].add + Node[R].del); 43 } 44 45 power Merge(int L, int R) 46 { 47 power c = (power){0, 0, 0}; 48 if(Node[L].add <= Node[R].del) 49 c.del = Node[L].del + Node[R].del - Node[L].add, 50 c.add = Node[R].add, c.val = Node[R].val; 51 if(Node[L].add > Node[R].del) 52 { 53 c.del = Node[L].del; 54 c.add = Node[L].add - Node[R].del + Node[R].add; 55 c.val = Query(L, Node[R].del) + Node[R].val; 56 } 57 return c; 58 } 59 60 void Build(int i, int l, int r) 61 { 62 if(l == r) 63 { 64 if(oper[l].opt == 0) Node[i] = (power){1, 0, oper[l].val}; 65 else Node[i] = (power){0, oper[l].val, 0}; 66 return; 67 } 68 int mid = l + r >> 1; 69 Build(i << 1, l, mid); Build(i << 1 | 1, mid + 1, r); 70 Node[i] = Merge(i << 1, i << 1 | 1); 71 72 } 73 74 void Update(int i, int l, int r, int L) 75 { 76 if(L <= l && r <= L) 77 { 78 if(oper[l].opt == 0) Node[i] = (power){1, 0, oper[l].val}; 79 else Node[i] = (power){0, oper[l].val, 0}; 80 return; 81 } 82 int mid = l + r >> 1; 83 if(L <= mid) Update(i << 1, l, mid, L); 84 else Update(i << 1 | 1, mid + 1, r, L); 85 Node[i] = Merge(i << 1, i << 1 | 1); 86 } 87 88 int main() 89 { 90 m = get(); T = get(); 91 for(int i = 1; i <= m; i++) 92 oper[i].opt = get(), oper[i].val = get(); 93 Build(1, 1, m); 94 while(T--) 95 { 96 int id = get(); 97 oper[id].opt = get(); oper[id].val = get(); 98 Update(1, 1, m, id); 99 printf("%d ", Node[1].val); 100 } 101 }