2017暑期集训Day 25 树状数组
2017-08-08 19:55
387 查看
poj 2352 && hdu 1541 Stars
[Solution]对于每个点,询问在其左下角的点的数量,我们按照y方向排序,这样按照升序方向遍历可以确保后面的点的纵坐标比前面的大,我们把前面的点的横坐标存到树状数组里,这样每次取出横坐标比其小的数量即可
[code]#include<cstdio> #include<iostream> #include<vector> #include<cstring> #include<cmath> #include<algorithm> #include<string> using namespace std; #define N 52505 int n, m, l, r; int a , c ; int lowbit(int x) { return x & -x; } int sum(int x) { int ret = 0; while(x > 0){ ret += c[x]; x -= lowbit(x); } return ret; } void add(int x) { while(x <= 32005){ c[x]++; x += lowbit(x); } } int main() { //freopen("b.in", "r", stdin); while(~scanf("%d", &n) && n){ for(int i = 0; i <= 32005; i++) { c[i] = 0; a[i] = 0; } for(int i = 1; i <= n; i++){ int x, y; scanf("%d%d", &x, &y); x++; y = sum(x); a[y]++; add(x); } for(int i = 0; i < n; i++) printf("%d\n", a[i]); } return 0; }
HDU 2838-Cow Sorting
[Solution]树状数组求解逆序对
[code]#include<cstdio> #include<iostream> #include<vector> #include<cstring> #include<cmath> #include<algorithm> #include<string> using namespace std; typedef long long ll; #define N 102505 int n, m, l, r, delta; long long c , d ; int a ; int lowbit(int x) { return x & -x; } ll sum(int x) { ll ret = 0; while(x > 0){ ret += c[x]; x -= lowbit(x); } return ret; } void add(int x) { while(x <= n){ c[x] += delta; x += lowbit(x); } } ll sumd(int x) { ll ret = 0; while(x > 0){ ret += d[x]; x -= lowbit(x); } return ret; } void addd(int x) { while(x <= n){ d[x]++; x += lowbit(x); } } int main() { // freopen("b.in", "r", stdin); scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", a + i); long long ans = 0; for(int i = n; i >= 1; i--){ ans += 1LL * a[i] * sumd(a[i] - 1) + sum(a[i] - 1); delta = a[i]; add(a[i]); addd(a[i]); } cout << ans << endl; return 0; }
HDU - 1556 Color the ball
[Solution]区间修改,单点查询
[code]#include<cstdio> #include<iostream> #include<vector> #include<cstring> #include<cmath> #include<algorithm> #include<string> using namespace std; #define N 102505 int n, m, l, r, delta; int a , c ; int lowbit(int x) { return x & -x; } int sum(int x) { int ret = 0; while(x > 0){ ret += c[x]; x -= lowbit(x); } return ret; } void add(int x) { while(x <= n){ c[x] += delta; x += lowbit(x); } } int main() { // freopen("b.in", "r", stdin); while(~scanf("%d", &n) && n){ for(int i = 1; i <= n; i++) c[i] = 0; for(int i = 1; i <= n; i++){ scanf("%d%d", &l, &r); delta = 1 4000 ; add(l); if (r + 1 <= n){ delta = -1; add(r + 1); } } for(int i = 1; i < n; i++) printf("%d ", sum(i)); printf("%d\n", sum(n)); } return 0; }
POJ 2299 Ultra-QuickSort (归并排序求逆序数)
[Solution]需要离散化
[code]#include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define N 502000 typedef long long ll; int n, m, l, r; int a , c ; struct node{ int w, num; } b ; int lowbit(int x) { return x & -x; } int sum(int x) { int ret = 0; while(x > 0){ ret += c[x]; x -= lowbit(x); } return ret; } void add(int x) { while(x <= n){ c[x] ++; x += lowbit(x); } } bool cmp(node a, node b){ return a.w < b.w; } int main() { // freopen("b.in", "r", stdin); while(~scanf("%d", &n) && n){ for(int i = 1; i <= n ;i++) c[i] = 0; for(int i = 1; i <= n; i++) { scanf("%d", &b[i].w); b[i].num = i; } sort(b + 1, b + n + 1, cmp); int cnt = 0; a[b[1].num] = ++cnt; for(int i = 2; i <= n; i++) { if (b[i].w == b[i - 1].w) a[b[i].num] = cnt; else a[b[i].num] = ++cnt; } ll ans = 0LL; for(int i = n; i >= 1; i--){ int x = a[i]; ans += sum(x - 1); add(x); } cout << ans << endl; } return 0; }
HDU 5862 Counting Intersections
[Problem]给定n(1e5)个平行于坐标轴的线段,询问交点个数。
[Solution]
扫描线+树状数组
我们按照x方向枚举平行与y轴的线段,我们需要得到的是在此时[y1, y2] 有多少个横向线段相交,因此我们对于每个横向线段,只保留两个点,在lx 的时候对应y 的位置数量+1, 在rx+1的位置上对应y数量-1,这样用树状数组维护y值对应的短点数量即可
[code]#include<cstdio> #include<iostream> #include<vector> #include<cstring> #include<cmath> #include<algorithm> #include<string> #include<set> #include<map> using namespace std; typedef long long ll; #define N 402000 int n, m, k, cnt, T, num, delta; int a , c ; struct node{ int num, y, y1, y2, x; } point ; int lowbit(int x) { return x & -x; } int bitsum(int x) { int ret = 0; while(x > 0){ ret += c[x]; x -= lowbit(x); } return ret; } void add(int x) { while(x <= cnt){ c[x] += delta; x += lowbit(x); } } bool cmp(node a, node b) { if (a.x == b.x) return a.num > b.num; return a.x < b.x; } int main() { // freopen("b.in", "r", stdin); scanf("%d", &T); while(T--){ scanf("%d", &n); int x1, x2, y1, y2; num = 0; set<int> dict; map<int, int> id; for(int i = 1; i <= n ;i++){ scanf("%d%d%d%d", &x1, &y1, &x2, &y2); if (!dict.count(y1)) dict.insert(y1); if (!dict.count(y2)) dict.insert(y2); if (x1 == x2){ num++; point[num].num = 1; point[num].y1 = min(y1, y2); point[num].y2 = max(y1, y2); point[num].x = x1; } else { num++; if (x1 > x2 ) { int t = x1; x1 = x2; x2 = t; } point[num].num = 3; point[num].y = y1; point[num].x = x1; num++; point[num].num = 2; point[num].y = y1; point[num].x = x2 + 1; } } ll ans = 0; cnt = 0; sort(point + 1, point + num + 1, cmp); for(set<int>::iterator it = dict.begin(); it != dict.end(); ++it) id[*it] = ++cnt; for(int i = 1; i <= cnt; i++) c[i] = 0; for(int i = 1; i <= num; i++){ if (point[i].num == 3){ int d = id[point[i].y]; delta = 1; add(d); } else if (point[i].num == 2){ int d = id[point[i].y]; delta = -1; add(d); } else{ int y1 = point[i].y1, y2 = point[i].y2; y1 = id[y1]; y2 = id[y2]; ll tot = bitsum(y2) - bitsum(y1 - 1); ans += 0LL + bitsum(y2) - bitsum(y1 - 1); } } cout << ans << endl; } return 0; }
ZOJ3672:Gao The Sequence
[Problem]给定n(2e5)个数,询问多少个子区间[l. r] 的算数平均值大于k
[Solution]
∑ai >= (r - l + 1) * k ∑(ai - k) >= 0 令b[i] = a[i] - k 令sum[i] = ∑b[i] 原式为sum[r] - sum[l - 1] >= 0 -> sum[r] >= sum[l - 1]
这样我们从小到大枚举r, 每次取出小于sum[r]的数量,然后把sum[r] 加入到bit 中即可
令sum[i] =∑a[i] sum[r] - sum[l - 1] >= (r - l + 1) * k sum[r] - r * k >= sum[l - 1] - (l - 1) * k b[i] = sum[i] - i * k; b[r] >= b[l] (0 <= l < r)
[code]#include<cstdio> #include<iostream> #include<vector> #include<cstring> #include<cmath> #include<algorithm> #include<string> #include<set> #include<map> using namespace std; typedef long long ll; #define N 202500 int n, m, k, cnt; ll c ; int a ; ll sum ; int lowbit(int x) { return x & -x; } ll bitsum(int x) { ll ret = 0; while(x > 0){ ret += c[x]; x -= lowbit(x); } return ret; } void add(int x) { while(x <= cnt){ c[x] ++; x += lowbit(x); } } int main() { // freopen("b.in", "r", stdin); scanf("%d%d", &n, &k); for(int i = 1; i <= n; i++) scanf("%d", a + i); sum[0] = 0LL; set<ll> dict; dict.insert(0); for(int i = 1; i <= n; i++) { a[i] = a[i] - k; sum[i] = sum[i - 1] + a[i]; if (!dict.count(sum[i])) dict.insert(sum[i]); } map<ll , int > id; cnt = 0; ll ans = 0LL; for(set<ll>::iterator it= dict.begin(); it != dict.end(); ++it) id[*it] = ++cnt; add(id[0]); for(int i = 1; i <= n; i++){ int x = id[sum[i]]; ans += bitsum(x); add(x); } cout << ans; return 0; }
afe4
相关文章推荐
- [ 后缀自动机 树上启发式合并 线段树 树状数组 ] [ 雅礼集训 2017 Day7 ] LOJ#6041
- 2017暑期ACM俱乐部个人训练赛第2场 G题 Balanced Photo(树状数组求逆序对)
- 2017暑期集训Day 9 递推
- 2017暑期集训 Day 3 搜索与并查集
- 2017暑期集训 Day 3
- 2017暑期集训Day 11 背包
- 2017暑期集训Day 14 区间dp+二分图匹配
- [ZJOI2017] 树状数组
- 概率+树套树——UOJ#291/Luogu3688 [ZJOI2017]树状数组
- 【NOIP2017提高A组集训10.25】天才绅士少女助手克里斯蒂娜(树状数组)
- 陕西省集训之树状数组
- [BZOJ4889][洛谷P3759][TJOI2017]不勤劳的图书管理员 分块+树状数组
- 暑假集训日记--8.16--练习赛题+树状数组
- 2016-2017 HPU暑期集训练习赛
- [P4064][JXOI2017]加法(贪心+树状数组+堆)
- HDU 6078 Wavel Sequence (dp + 树状数组, 2017 Multi-Univ Training Contest 4)
- 2017 ACM-ICPC乌鲁木齐网络赛 G. Query on a string 【KMP+树状数组】
- 【uoj291】 ZJOI2017—树状数组
- BZOJ4888 [Tjoi2017]异或和 【树状数组】
- ZUFE 2017院赛 - Problem M: 图样图森破(树状数组)