CF961E Tufurama
思路
个人觉得主席树比较好想,而且代码非常简单,仅需 \(37\) 行。
我们不妨枚举 \(j\),这样 \(i\) 的范围就被确定在了 \(1\) 至 \(\min(j-1,a_j)\),也就是说我们需要查询的内容就是所有 \(1 \le i \le \min(j-1,a_j)\) 且 \(a_i \ge j\) 的 \(i\) 的个数。
于是主席树维护即可,时空复杂度 \(\mathcal O(n \log n)\)。
代码
#include<bits/stdc++.h>
using namespace std;
int const N=2e5+10;
int n,cnt=1,a[N],c[N*50],root[N*50],lc[N*50],rc[N*50];
#define ls (lc[x])
#define rs (rc[x])
#define mid ((l+r)>>1)
inline int clone(int x){lc[++cnt]=lc[x];rc[cnt]=rc[x];c[cnt]=c[x];return cnt;}
inline int update(int la,int l,int r,int p){
int x=clone(la);
if (l==r){++c[x];return x;}
if (p<=mid) ls=update(lc[la],l,mid,p);
else rs=update(rc[la],mid+1,r,p);
c[x]=c[ls]+c[rs];
return x;
}
inline int query(int x,int l,int r,int p){
if (!x) return 0;
if (l==r) return c[x];
if (p<=mid) return query(ls,l,mid,p)+c[rs];
else return query(rs,mid+1,r,p);
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n;root[0]=1;
long long ans=0;
for (int i=1;i<=n;++i) cin>>a[i];
for (int i=1;i<=n;++i)
root[i]=update(root[i-1],1,1e9,a[i]);
for (int i=2;i<=n;++i){
int lim=min(a[i],i-1);
ans+=query(root[lim],1,1e9,i);
}
cout<<ans<<'\n';
return 0;
}

浙公网安备 33010602011771号