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;
}
posted @ 2022-11-04 10:41  Tx_Lcy  阅读(40)  评论(0)    收藏  举报