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;
}