您的位置:首页 > 其它

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj