2020牛客寒假算法基础集训营4 H 坐火车

https://ac.nowcoder.com/acm/contest/3005/H

 

当我们要计算的车厢从第i个移到第i+1个的时候

只会影响第i个车厢对应颜色的数量 和 第i+1个车厢对应颜色的数量

用树状数组维护当前车厢左右所有颜色相同的车厢对数的前缀和

假设已经计算完了前i个车厢的答案,现在要计算第i+1个车厢的答案

若车厢i的颜色是a,车厢i+1的颜色是b

除了a、b,其他颜色的左右相同的车厢对数是一样的

对颜色a来说,第i个车厢可以做 左边那个车厢了

第i个车厢后面有多少个颜色跟他一样的车厢(除去第i+1个车厢),这个颜色对答案的贡献就会增加多少

对颜色b来说,第i+1个车厢不可以做 右边那个车厢了

第i+1个车厢前面有多少个颜色跟他一样的车厢(除去第i个车厢),这个颜色对答案的贡献就会减少多少

再用两个数组记录这个即可

 

有一个点想了很久:

求第i个车厢后面有多少个颜色跟他一样的车厢(除去第i+1个车厢)时,可以不用管“除去第i+1个车厢”这个条件

后面也是

因为如果第i和第i+1个车厢颜色相同,一加一减恰好抵消

 

#include<cstdio>
#include<algorithm>
using namespace std;

#define N 500001

#define lowbit(x) x&-x

int col[N],L[N],R[N];
int suml[N],sumr[N];

long long c[N];

void add(int x,int y)
{
    while(x<N)
    {
        c[x]+=y;
        x+=lowbit(x);
    }
}

long long query(int x)
{
    long long s=0;
    while(x)
    {
        s+=c[x];
        x-=lowbit(x);
    }
    return s;
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%d%d%d",&col[i],&L[i],&R[i]);
        sumr[col[i]]++;
    }
    for(int i=1;i<=n;++i)
    {
        sumr[col[i]]--;
        add(col[i],-suml[col[i]]);
        printf("%lld ",query(R[i])-query(L[i]-1));
        suml[col[i]]++;
        add(col[i],sumr[col[i]]);
    }
    return 0;
}

 

posted @ 2020-02-13 10:42  TRTTG  阅读(157)  评论(0编辑  收藏  举报