Codeforces 961E 树状数组,思维

E. Tufurama

题意:
n 个数 a[],要你找有多少个点对(x, y),其中 x<y,a[x]>=y,a[y]>=x 。
tags:
1】比较直观的一种做法,离散化,然后按 min(a[y], y-1) 排序,排序后对于每一个询问,我们更新树状数组到 min(a[y], y-1) 即可。查询就是 Sum(N-1)-Sum(y-1) 。

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 500005;

ll  bit[N];
void Add(int x, ll y) {
    for( ; x<N; x+=x&-x) bit[x] += y;
}
ll  Sum(int x) {
    ll  ret = 0; for( ; x; x-=x&-x) ret += bit[x]; return ret;
}

int n;
ll  a[N];
struct Item {
    ll  ai, bi; int id;
    bool friend operator < (Item a, Item b) {
        return a.bi < b.bi;
    }
} p[N];

map< ll, int > mp;   int tot;
int get_id(ll x) {
    return  (mp.find(x)==mp.end()) ? (mp[x]=++tot) : mp[x];
}
ll  b[N];
void Init_id() {
    int cnt = 0;
    rep(i,1,n) b[++cnt]=a[i], b[++cnt]=i;
    b[++cnt] = 0;
    sort(b+1, b+1+cnt);
    rep(i,1,cnt) get_id(b[i]);
}

int main()
{
    scanf("%d", &n);
    rep(i,1,n) {
        scanf("%lld", &a[i]);
        p[i] = (Item){ a[i], min(1LL*(i-1), a[i]), i };
    }
    Init_id();
    sort(p+1, p+1+n);
    ll  ans = 0;
    int now = 1;
    rep(i,1,n)
    {
        for( ; now<=p[i].bi; ++now) Add(get_id(a[now]), 1);
        ans += Sum(N-1)-Sum(get_id(p[i].id-1));
    }
    printf("%lld
", ans);

    return 0;
}

2】还有一种更灵活的做法,把每个 x 存入到对应的 a[x] (如a[x]>n就当作n处理)里,然后 for(y) 从 n 到 1 ,对于每个 y 我们在对应的所有 x 上 +1 ,然后直接询问 Sum(min(y-1, a[y])) 就好。

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 500005;

ll  bit[N];
void Add(int x, ll y) {
    for( ; x<N; x+=x&-x) bit[x]=(bit[x]+y);
}
ll  Sum(int x) {
    ll  ret = 0; for( ; x; x-=x&-x) ret=(ret+bit[x]); return ret;
}

int n, a[N];
vector< int > ve[N];
int main()
{
    scanf("%d", &n);
    rep(i,1,n) {
        scanf("%d", &a[i]);
        if(a[i]<n) ve[a[i]].PB(i);
        else  ve[n].PB(i);
    }
    ll  ans = 0;
    per(i,n,1) {
        for(int x : ve[i]) Add(x, 1);
        ans += Sum(min(i-1, a[i]));
    }
    printf("%lld
", ans);

    return 0;
}
原文地址:https://www.cnblogs.com/sbfhy/p/8732923.html