UVA 1513-Movie collectio(树状数组)

理解树状数组的模板:就三部分组成:lowbit函数,区间求和函数( sum() ),单点更新函数( add() ),这表明了每改变区间中的某个点就必须调用一下add函数,因为一个点的改变会造成所有c数组里面其它元素的改变。那么什么是c数组呢?

这个就是虚拟的一个数组,不知道为什么的可以去网上搜一下lowbit函数的原理,因为我们就是靠它来构造c数组。

接着关于区间求和,我们是直接用sum(x)-sum(y)来得到[x,y]这一段区间的和。

好了,树状数组模板介绍完毕,接下来是关于这道题目:

思路:此题让我们求的是连续的一些数1,2,3……n,对于每个数求在其前面有几个数,并输出,接着把该数放到第一位去,其它数字相应后移。这题的思路可以这样:

初始的时候,题目告诉我们有一串数是1234……n,我们将它反过来看:n,n-1,n-2……3,2,1,反过来以后其对应位置(pos)为:1,2,3,4……n

for example:

假设n=6,m=3,令a数组为:11111100000………………(把a数组开大一点,预留至少n+m个空位),每一位代表了6,5,4,3,2,1...

令pos[6]=1,pos[5]=2,pos[4]=3,pos[3]=4,pos[2]=5,pos[1]=6;

求和可得到:sum[pos[1]]=6,sum[pos[2]]=5,sum[pos[3]]=4……sum[pos[n]]=1; 

假设查询为6 4 2,则第一次输出sum[pos[n+m]]-sum[pos[6]]=6-1=5;然后我们调用add函数进行单点修改(只有用了树状数组的单点修改才能用它的区间求和):

add(pos[6],-1); ------------------------------------------------------------------------------ 这一步表示原来位置上的6被移走,原位置减1变成0

int len=n+1,pos[6]=len++;-----------------------------------------------------------------这一步表示6被移到新位置

add(pos[6],1);---------------------------------------------------------------------------------这一步表示新位置加1

第二次操作:输出sum[pos[n+m]]-sum[pos[4]]=6-2=4;然后我们调用add函数进行单点修改:

add(pos[4],-1); ------------------------------------------------------------------------------ 这一步表示原来位置上的4被移走,原位置减1变成0

pos[4]=len++;-----------------------------------------------------------------这一步表示4被移到新位置

add(pos[4],1);---------------------------------------------------------------------------------这一步表示新位置加1

第三次操作:输出sum[pos[n+m]]-sum[pos[2]]=6-2=4;然后我们调用add函数进行单点修改:

add(pos[2],-1); ------------------------------------------------------------------------------ 这一步表示原来位置上的4被移走,原位置减1变成0

pos[2]=len++;-----------------------------------------------------------------这一步表示4被移到新位置

add(pos[2],1);---------------------------------------------------------------------------------这一步表示新位置加1

输出的是5 4 4

代码:

#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<queue>
#include<algorithm>
#include<iostream>
#include<math.h>
#define maxn 300008
#define ll long long
#define RPG(i,a,b) for(int i=(a);i<(b);i++)
using namespace std;
int n,a[maxn],c[maxn];

int lowbit(int x)
{
    return (x&(-x));
}

int sum(int x)
{
    int ret=0;
    while(x>0)
    {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}

int add(int x,int d)
{
    while(x<=n)
    {
        c[x]+=d;
        x+=lowbit(x);
    }
}

const int N = 3e5+7;
int len;
int pos[N];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset( c, 0, sizeof(c) );
        int m;
        scanf("%d%d",&n,&m);
        len = n+1;
        n += m;
        RPG(i,1,len)
        {
            add(i,1);
            pos[i] = len-i;
        }
        
        int f=1;
        RPG(i,0,m)
        {
            int x;
            scanf("%d",&x);
            if(f)
            {
                f=0;
                printf("%d",sum(n)-sum(pos[x]));
            }
            else
                printf(" %d",sum(n)-sum(pos[x]));
            
            add( pos[x], -1 );
            pos[x] = len++;
            add( pos[x], 1 );
        }
        puts("");
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/pipitongkw1/article/details/81912739