codeforces 961E Tufurama
题目链接:http://codeforces.com/contest/961/problem/E
题意:给你n个数ai,(n<=2e5,1<=ai<=1e9)然后问你在这n个数中,有多少对i,j(i<j)满足ai>=j&&aj>=i。输出对数即可
分析:首先我们知道对于满足要求的i,j,我们需要满足ai>j和aj>i。然后我们枚举i,那么可以确定j的范围是1到ai。我们可以枚举1到ai范围内的j可以求出每个与i满足的个数,这样时间复杂度是O(n²),显然要T。仔细一想,我们的i是递增+1枚举,因此我们可以每次枚举完之后删除等于i的数就可以了。我们需要区间查询和单点更新(树状数组就可以了)。由于i是从1开始到n,我们在每次查询完之后,删除aj等于i的数字,完成更新。这样可以保证我们下次枚举i+1的时候,查询得到的aj一定是大于i+1的。然后我们需要去除i和i对,然后除以2以确保i<j。(我的数据结构是真的菜,一般都是靠躺)
AC代码:
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 long long a[200005]; 6 int n; 7 vector<int>G[200005]; 8 int lowbit(int x){ 9 return x&(-x); 10 } 11 void update(int x,long long d){ 12 while(x<=n){ 13 a[x]+=d; 14 x+=lowbit(x); 15 } 16 } 17 long long query(int x){ 18 long long sm=0; 19 while(x){ 20 sm+=a[x]; 21 x-=lowbit(x); 22 } 23 return sm; 24 } 25 int b[200005]; 26 int main(){ 27 ios_base::sync_with_stdio(0); 28 cin.tie(0); 29 memset(a,0,sizeof(a)); 30 cin>>n; 31 n++; 32 for(int i=1;i<n;i++){ 33 cin>>b[i]; 34 if(b[i]>=n){ 35 b[i]=n; 36 } 37 G[b[i]].push_back(i); 38 update(i,1); 39 } 40 long long result=0; 41 for(int i=1;i<n;i++){ 42 long long sm1=query(b[i]); 43 result+=sm1; 44 if(b[i]>=i) result--; 45 int d=G[i].size(); 46 for(int j=0;j<d;j++){ 47 update(G[i][j],-1); 48 } 49 } 50 cout<<result/2<<endl; 51 return 0; 52 }