CF961E Tufurama
链接:
题意:
给出长度为 \(n(1\leq n\leq 2\times10^5)\) 的序列 \(a(1\leq a_i\leq10^9)\),求满足 \(1\leq i< j\leq n\) 且 \(a_i\geq j,a_j\geq i\) 的二元组 \((i,j)\) 的数量。
分析:
对于一个位置 \(j\),考虑它前面所有能与它满足条件的 \(i\) 的数量,于是有 \(i< j\) 和 \(a_j\geq i\) 所以只考虑 \([1,\min(j-1,a_j)]\) 位置的数,同时需要满足 \(a_i\geq j\)。所以我们要做的是从前往后扫一遍,对于每个位置 \(j\),求出 \([1,\min(j-1,a_j)]\) 中 \(a_i\geq j\) 的 \(i\) 的数量。可以对每个位置建一棵权值线段树记录 \([1,j]\) 中的所有 \(a_i\),使用主席树就可以 \(O(n\log n)\) 过掉此题。注意要对 \(a\) 序列离散化,且由于要比较 \(a_i\) 和 \(j\) 所以在离散化时要注意同时离散化 \([1,n]\)。
代码:
#include<bits/stdc++.h>
using namespace std;
#define in read()
inline int read(){
int p=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();}
return p*f;
}
const int N=4e5+5;
int n,a[N],q[N],qn;
long long ans;
inline int bin(int key){
int l=1,r=qn,mid;
while(l<r){
mid=(l+r)>>1;
if(q[mid]<key)l=mid+1;
else r=mid;
}
return l;
}
//sgt--------------------
int rt[N],sum[N<<5],lc[N<<5],rc[N<<5],tot;
void pushup(int p){sum[p]=sum[lc[p]]+sum[rc[p]];}
int newnode(){
sum[++tot]=lc[tot]=rc[tot]=0;
return tot;
}
int built(int l,int r){
int p=newnode();
if(l==r)return p;
int mid=(l+r)>>1;
lc[p]=built(l,mid);
rc[p]=built(mid+1,r);
return p;
}
int newbuilt(int pre,int l,int r,int x,int d){
int now=newnode();
sum[now]=sum[pre];
lc[now]=lc[pre];
rc[now]=rc[pre];
if(l==r){sum[now]+=d;return now;}
int mid=(l+r)>>1;
if(x<=mid)lc[now]=newbuilt(lc[now],l,mid,x,d);
else rc[now]=newbuilt(rc[now],mid+1,r,x,d);
pushup(now);
return now;
}
int query(int l,int r,int p,int ql,int qr){
if(l>=ql&&r<=qr)return sum[p];
int mid=(l+r)>>1,res=0;
if(ql<=mid)res+=query(l,mid,lc[p],ql,qr);
if(qr>mid)res+=query(mid+1,r,rc[p],ql,qr);
return res;
}
//-----------------------------------
signed main(){
n=in;
for(int i=1;i<=n;i++)a[i]=in,q[i]=a[i];
for(int i=1;i<=n;i++)q[i+n]=i;
sort(q+1,q+1+2*n);
qn=unique(q+1,q+1+2*n)-(q+1);
for(int i=1;i<=n;i++)a[i]=bin(a[i]);
rt[0]=built(1,qn);
for(int i=1;i<=n;i++){
int t=min(i-1,a[i]);
ans+=query(1,qn,rt[t],i,qn);
rt[i]=newbuilt(rt[i-1],1,qn,a[i],1);
}
cout<<ans;
return 0;
}