2017暑期集训Day 25 树状数组

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[N], c[N];
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[N], d[N];
int a[N];
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[N], c[N];
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;
            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[N], c[N];
struct node{
  int w, num;
} b[N];
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[N], c[N];
struct node{
  int num, y, y1, y2, x;
} point[N];
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[N];
int a[N];
ll sum[N];
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值