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\n", 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\n", ans);

    return 0;
}

转载于:https://www.cnblogs.com/sbfhy/p/8732923.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
树状数组(Fenwick Tree)是一种用于高效处理区间和查询的数据结构,常用于解一维数组的前缀和、区间更新和查询等问题。 在 Codeforces 上,树状数组常被用来解决一些与区间和查询有关的问题。它可以在 O(logn) 的时间内完成单点更新和查询,以及区间求和等操作。 下面是一个简单的示例代码,展示了如何实现一个基本的树状数组: ```cpp #include <iostream> #include <vector> using namespace std; // 获取最低位的 1 int getLowbit(int x) { return x & -x; } // 树状数组的单点更新操作 void update(vector<int>& fenwick, int index, int delta) { while (index < fenwick.size()) { fenwick[index] += delta; index += getLowbit(index); } } // 树状数组的前缀和查询操作 int query(vector<int>& fenwick, int index) { int sum = 0; while (index > 0) { sum += fenwick[index]; index -= getLowbit(index); } return sum; } int main() { int n; cin >> n; vector<int> fenwick(n + 1, 0); // 初始化树状数组 for (int i = 1; i <= n; i++) { int val; cin >> val; update(fenwick, i, val); } // 进行查询操作 int q; cin >> q; while (q--) { int type; cin >> type; if (type == 1) { int index, delta; cin >> index >> delta; update(fenwick, index, delta); } else if (type == 2) { int l, r; cin >> l >> r; int sum = query(fenwick, r) - query(fenwick, l - 1); cout << sum << endl; } } return 0; } ``` 在这个示例中,我们使用了一个长度为 n 的数组 `fenwick` 来表示树状数组。`update` 函数用于更新树状数组中的某个元素,`query` 函数用于查询树状数组中某个区间的和。 你可以根据具体问题的要求进行相应的修改和扩展。希望对你有所帮助!如果有任何疑问,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值