zoukankan      html  css  js  c++  java
  • 2020牛客寒假算法基础集训营4 H.坐火车(树状数组/线段树)

    感觉网上的题解都略微简略包括官方题解,所以打算写一个尽可能详细的

    题目链接:https://ac.nowcoder.com/acm/contest/3005/H

    题意:

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

    思路: 

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

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

    之后我们在树状数组中减去pre[color[i]]也就是在x之前与x颜色相同的车厢,因为统计的对数是要求在x的两边,所以我们得减去与x匹配的个数

    然后就可以在树状数组中查询区间[li , ri]对数了

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

    #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;
     }
  • 相关阅读:
    穷举法和搜索法的统计三角形
    2015.5.21 Core Java Volume 1
    我喜欢出发
    MeshLab中画面在前面加个f的代码
    【axel帮助代码】为了在单位正方形里面画一个洞 ,网上获取了此代码。
    uniapp 发起网络请求
    qt 取进程列表,读写内存, 写字节集
    qt 注册热键
    qt 获取窗口句柄的线程id和进程id GetWindowThreadProcessId
    qt 向窗口发送消息,键盘输入事件
  • 原文地址:https://www.cnblogs.com/overrate-wsj/p/12299843.html
Copyright © 2011-2022 走看看