UValive 4329 --树状数组入门

题目链接:https://vjudge.net/contest/238229#problem/D

白书上树状数组的例题,刚好学完,正好熟悉一下树状数组的常规操作。

对于每个i当裁判时的情况,设从a1到ai-1有ci个小于ai的数,则就有i-1-ci个比ai大的数,从ai+1到an有di个小于ci的数,就有n-i-di个比ai大的数,这样,大数与小数配对,小数与大数配对,就有ci*(n-i-di)+di*(i-1-ci)种不同的组法,问题就变成求ci和di。

如何求ci和di呢?从0到ai的最大值1e5遍历一遍,如果这个值存在(判断在a[i]中是否出现),x[a[i]]=1,否则等于0,这样,小于a[i]的值的个数就变为x[1]+x[2]+......+x[a[i]-1](仔细想想),那么问题就变成如何求x[i]得前缀和了,就可以用树状数组求了。具体实现就是,输入一个a[i],将它用add操作加入到树状数组中,用sum求前缀和。还有很多细节,看代码吧。

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

typedef long long ll;
const int maxn=2e4+10;
const int maxm=1e5+10;
int n;

int c[maxn];
int d[maxn];//标号小于和大于i的,技能值比ai小的个数
int a[maxn];
int s[maxm];//树状数组

int lowbit(int x)
{
    return x&-x;
}
int sum(int x)
{
    int ret=0;
    while(x>0)
    {
        ret+=s[x];
        x-=lowbit(x);//向左递推,求和
    }
    return ret;
}

void add(int x,int d)
{
    while(x=1;i--)
        {
            add(a[i],1);
            d[i]=sum(a[i])-1;//后缀和,满足d[i]数组的定义
        }
        ll ans=0;
        for(int i=2;i

 

你可能感兴趣的:(树状数组)