题目链接:
题目描述:
有一段区间,对这段区间有两种操作。1:插入操作,第i次插入长度为i的线段,并询问被当前线段完全覆盖的线段数目。
2:删除操作,删除第b次插入的线段。
解题思路:
对于当前新插入线段,只需要统计已插入线段中右端点小于该线段右端点的数目,以及左端点小于该线段做端点的数目,两者相减即可。还有就是离散化问题,sort+unique+map真的是离散化利器(啧啧啧~)。
1 #include <map> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxn = 200005; 9 typedef long long LL; 10 struct opera 11 { 12 int a, l, r; 13 }p[maxn]; 14 int cl[maxn], cr[maxn], al[maxn], ar[maxn], L[maxn]; 15 //树状数组不能从0开始 16 int lowbit (int x) 17 { 18 return x & (-x); 19 } 20 21 int sum (int x, int a[]) 22 { 23 int Sum = 0; 24 while (x > 0) 25 { 26 Sum += a[x]; 27 x -= lowbit(x); 28 } 29 return Sum; 30 } 31 32 void change (int i, int x, int a[], int n) 33 { 34 while (i <= n) 35 { 36 a[i] += x; 37 i += lowbit(i); 38 } 39 } 40 41 int main () 42 { 43 int n, m, cnt, t, cas = 0; 44 while (scanf ("%d", &t) != EOF) 45 { 46 memset (cl, 0, sizeof(cl)); 47 memset (cr, 0, sizeof(cr)); 48 n = m = cnt = 0; 49 50 for (int i=0; i<t; i++) 51 { 52 scanf ("%d %d", &p[i].a, &p[i].l); 53 if (p[i].a == 0) 54 { 55 cnt ++; 56 p[i].r = p[i].l + cnt; 57 al[n++] = p[i].l; 58 ar[m++] = p[i].r; 59 L[cnt] = p[i].l; 60 } 61 } 62 63 sort (al, al+n); 64 n = unique (al, al+n) - al; 65 sort (ar, ar+m); 66 m = unique (ar, ar+m) - ar; 67 map <int, int> ml, mr; 68 69 for (int i=0; i<n; i++) 70 ml[al[i]] = i + 1; 71 for (int i=0; i<m; i++) 72 mr[ar[i]] = i + 1; 73 74 cnt = 0; 75 printf ("Case #%d: ", ++cas); 76 for (int i=0; i<t; i++) 77 { 78 if (p[i].a) 79 { 80 81 int left = ml[L[p[i].l]]; 82 int right = mr[L[p[i].l]+p[i].l]; 83 change (left, -1, cl, n); 84 change (right, -1, cr, m); 85 } 86 else 87 { 88 int ansl = sum (ml[p[i].l]-1, cl); 89 int ansr = sum (mr[p[i].r], cr); 90 printf ("%d ", ansr - ansl); 91 change (ml[p[i].l], 1, cl, n); 92 change (mr[p[i].r], 1, cr, m); 93 } 94 } 95 } 96 return 0; 97 }
好久没有写过树状数组了,基本忘光光>_<.....,今天算是从新温习了一下(感觉这个代码好渣,改天再改一下)