题意:
给出一个n个数的序列,求有几对(i,j)满足a[i]>=j&&a[j]>=i,(i,j)和(j,i)只能算一对。
考虑第i个数会有几个j(j<i)满足条件,首先a[i]>=j就是查询的区间就是[1,a[i]],a[j]>i也就是查询区间[1,a[i]]中有几个a[j]>=i。
岂不主席树?注意去重就行了。
//by zykykyk
#include<cstdio>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string>
#define rg register
#define il inline
#define vd void
#define ll long long
#define N 200010
#define For(i,x,y) for (rg ll i=(x);i<=(y);i++)
#define Dow(i,x,y) for (rg int i=(x);i>=(y);i--)
#define cross(i,k) for (rg int i=first[k];i;i=last[i])
using namespace std;
il ll max(ll x,ll y){return x>y?x:y;}
il ll min(ll x,ll y){return x<y?x:y;}
il ll read(){
ll x=0;int ch=getchar(),f=1;
while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
if (ch=='-'){f=-1;ch=getchar();}
while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
int n,tot,a[N];
ll ans;
int sum,rt[N],v[N*33],lson[N*33],rson[N*33];
il vd insert(int &u,int last,int l,int r,int k){
u=++sum,v[u]=v[last]+1;
if (l==r) return;
lson[u]=lson[last],rson[u]=rson[last];int mid=l+r>>1;
if (k<=mid) insert(lson[u],lson[u],l,mid,k);
else insert(rson[u],rson[u],mid+1,r,k);
}
il ll query(int u,int l,int r,int ql,int qr){
if (l>=ql&&r<=qr) return 1ll*v[u];
int mid=l+r>>1;
if (qr<=mid) return query(lson[u],l,mid,ql,qr);
else if (ql>mid) return query(rson[u],mid+1,r,ql,qr);
else return query(lson[u],l,mid,ql,qr)+query(rson[u],mid+1,r,ql,qr);
}
int main(){
n=read();
For(i,1,n) a[i]=read();
For(i,1,n) insert(rt[i],rt[i-1],1,1e9,a[i]);
For(i,1,n)
if (a[i]==i) ans+=query(rt[a[i]],1,1e9,i,1e9)-1;
else if (a[i]<i) ans+=query(rt[a[i]],1,1e9,i,1e9);
else ans+=query(rt[i],1,1e9,i,1e9)-1;
printf("%lld",ans);
}