2020牛客寒假算法基础集训营4 H.坐火车(树状数组/线段树)

感受网上的题解都略微简略包括官方题解,因此打算写一个尽量详细的ios

题目连接:https://ac.nowcoder.com/acm/contest/3005/H数组

 

题意:spa

每一个车箱都有三个参数,color,l,r,询问对于每一个车箱,在其两边的车箱有多少对车箱颜色相同,而且颜色的范围在[li , ri]内code

思路: blog

首先咱们定义几个数组,pre[i]表明整个数组的前缀中color[i]的个数,suf[i]表明整个数组的后缀中color[i]的个数,这读入的过程当中咱们就先统计suf数组,树状数组sum[i]记录每一个颜色的符合相求的对数是多少get

以后开始遍历color[i],对于每一个color咱们计算以前咱们就在suf数组中减去它,这样suf数组的意义就是在x以后各个颜色的个数string

以后咱们在树状数组中减去pre[color[i]]也就是在x以前与x颜色相同的车箱,由于统计的对数是要求在x的两边,因此咱们得减去与x匹配的个数it

而后就能够在树状数组中查询区间[li , ri]对数了io

在统计完以后就有很是重要的一步了,就是在树状数组中加入suf[color[i]]也就是i以后还有多少与i颜色相同的车箱,也就是i位置的贡献了class

 

#include<iostream>
#include<algorithm>
#include<cstring>
 using namespace std;
 typedef long long ll;
 const int maxn=5e5+10;
 ll pre[maxn],suf[maxn],sum[maxn];
 int n,l[maxn],r[maxn],color[maxn];
 int lowbit(int x){return x&(-x);}
 void add(int x,int val)
 {
     while(x<=n){
         sum[x]+=val;
         x+=lowbit(x);
     }
 }
 ll query(int x)
 {
     ll ans=0;
     while(x>=1){
         ans+=sum[x];
         x-=lowbit(x);
     }
    return ans;
 }
 int main()
 {
     scanf("%d",&n);
     for(int i=1;i<=n;i++){
         scanf("%d%d%d",&color[i],&l[i],&r[i]);
         suf[color[i]]++;
     }
    for(int i=1;i<=n;i++){
        suf[color[i]]--;
        add(color[i],-pre[color[i]]);
        printf("%lld ",query(r[i])-query(l[i]-1));
        pre[color[i]]++;
        add(color[i],suf[color[i]]);
    }
    return 0;
 }
相关文章
相关标签/搜索