Tufurama CodeForces

Tufurama CodeForces - 961E 

题意:有一部电视剧有n季,每一季有ai集。问有多少对i,j存在第i季第j集也同时存在第j季第i集。

思路:核心问题还是统计对于第i季,你要统计第i行(存在多少数量,要大于i)。 
线段树的维护相对而言比较暴力,树状数组的话,一开始全是1,一旦某个数过小,就会导致不构成贡献,移除就好。

线段树

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<cstdlib>
#include <vector>
#include<queue>
using namespace std;

#define ll long long
#define llu unsigned long long
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int maxn =  2e5+5;
const int  mod = 1e9+7;
int a[maxn];
vector<int>stk[maxn<<2];
void build(int x,int l,int r)
{
   if(l == r)
   {
       stk[x].push_back(a[l]);
       return;
   }
   for(int i = l;i<=r;i++)
       stk[x].push_back(a[i]);
   sort(stk[x].begin(),stk[x].end());
   int mid = (l+r)/2;
   build(x<<1,l,mid);
   build(x<<1|1,mid + 1,r);
}
int query(int L,int R,int l,int r,int i)
{
   if(L > R)
       return 0;
   if(L<=l && r<=R)
       return stk[i].size() - (lower_bound(stk[i].begin(),stk[i].end(),L-1) - stk[i].begin());
   int ans = 0;
   int mid = (l+r)/2;
   if(L <= mid)
       ans += query(L,R,l,mid,i<<1);
   if(R > mid)
       ans += query(L,R,mid+1,r,i<<1|1);
   return ans;
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    build(1,1,n);
    ll ans = 0;
    for(int i=1;i<n;i++)
        ans += query(i+1,min(a[i],n),1,n,1);
    printf("%lld
",ans);
}
View Code

树状数组

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<cstdlib>
#include <vector>
#include<queue>
using namespace std;

#define ll long long
#define llu unsigned long long
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int maxn =  2e5+5;
const int  mod = 1e9+7;

const int N=2e5+100;
int a[N],f[N];
struct node{
    int x,y;
}p[N];
bool cmp(node a,node b)
{
    if(a.y==b.y) return a.x<b.x;
    return a.y<b.y;
}
void add(int x,int y)
{
    while(x<N){
        f[x]+=y;
        x+=x&-x;
    }
}
int query(int x)
{
    int ans=0;
    while(x){
        ans+=f[x];
        x-=x&-x;
    }
    return ans;
}
int main ()
{
    int n;scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i]=min(a[i],n),p[i].x=i,p[i].y=a[i],add(i,1);
    sort(p+1,p+1+n,cmp);
    long long ans=0;
    int now=1;
    for(int i=1;i<=n;i++){
        while(now<=n && p[now].y<i) add(p[now++].x,-1);
        ans+=query(a[i]);
        if(a[i]>=i) ans--;
    }
    printf("%lld
",ans/2);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/smallhester/p/10300914.html