【Foreign】Weed [線段樹]
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,代表一個操作。
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)
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\n", Node[1].val); 100 } 101 }View Code
【Foreign】Weed [線段樹]