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 }
View Code
原文地址:https://www.cnblogs.com/ls961006/p/8782940.html