zoukankan      html  css  js  c++  java
  • Galahad

    牛客练习赛52 B题
    在这里插入图片描述
    题解我是一点没看懂,就算是有之前学习的树状数组我也没看懂 ,搞的我以为我连树状数组都不会了,然后又重新学了一点基础的
    必备知识技能 : 树状数组区间单点修改 , 区间查询
    可以先看一下这个题 ___HH的项链 , 几乎是一模一样的,上面的题解更是详细

    这个题的意思非常容易读懂, 就是在给你n个数,索引1 - n , 然后呢 , 给你m个询问,问你给定区间l-r内区间和为多少,但是这个区间里面如果有重复的数,这个数只能算一次
    首先区间和可以用差分,树状数组,线段树来做,但是这个题目要求所求区间里面的重复的数只能算一次;当时就尴尬了看了半天,最后有个网友推荐说是HH的项链,然后才看懂的

    核心的观点是

    对于一个含有重复数字的区间来说,因为重复的数只算一次,那么问题就在这,到底怎么处理这个重复的数字,大佬提供的方法就是只算重复数字最右边的一个,可能没听懂,当时我也没懂,举个例子就行了

    这个是洛谷上大佬(dlhham )的讲解:

    对于若干个询问的区间[l,r],如果他们的r都相等的话,那么项链中出现的同一个数字,一定是只关心出现在最右边的那一个的,例如:

    项链是:1 3 4 5 1

    那么,对于r=5的所有的询问来说,第一个位置上的1完全没有意义,因为r已经在第五个1的右边,对于任何查询的[L,5]区间来说,如果第一个1被算了,那么他完全可以用第五个1来替代。

    因此,我们可以对所有查询的区间按照r来排序,然后再来维护一个树状数组,这个树状数组是用来干什么的呢?看下面的例子:

    1 2 1 3

    对于第一个1,insert(1,1);表示第一个位置出现了一个不一样的数字,此时树状数组所表示的每个位置上的数字(不是它本身的值而是它对应的每个位置上的数字)是:1 0 0 0

    对于第二个2,insert(2,1);此时树状数组表示的每个数字是1 1 0 0

    对于第三个1,因为之前出现过1了,因此首先把那个1所在的位置删掉insert(1,-1),然后在把它加进来insert(3,1)。此时每个数字是0 1 1 0

    如果此时有一个询问[2,3],那么直接求sum(3)-sum(2-1)=2就是答案。

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    using namespace std;
    const int N = 5e5 + 10 ;
    typedef long long ll ;
    ll c[N] , ans[N] , vis[N];
    int a[N] ;
    int n , m ;
    ll lowbit(int x)
    {
    	return x & -x ;
    }
    struct node
    {
        int l , r , id ;
    }q[N];
    typedef long long ll ;
    void update(int x , int v)
    {
    	while(x <= n)
    	{
    		c[x] += v ;
    		x += lowbit(x) ;
    	}
    }
    bool cmp(node a , node b)
    {
      if(a.r == b.r) return a.l < b.l ;
      return a.r < b.r ;
    }
    ll ask(int x)
    {
    	ll ans = 0 ;
    	for(int i = x ;i  ;i -= lowbit(i))
    		ans += c[i] ; 
    	return ans ;
    }
    int main()
    {
    	scanf("%d%d" , &n , &m) ;
        for(int i = 1 ;i <= n ;i ++)
             scanf("%d" , &a[i]) ;
        for(int i = 1 ;i <= m ;i ++)
             scanf("%d%d" , &q[i].l , &q[i].r) , q[i].id = i ;
        sort(q + 1 , q + m + 1 , cmp) ;
        int tt = 1 ;
        for(int i = 1 ;i <= m ;i ++)
        {
            for( ;tt <= q[i].r ;tt ++)
            {
                if(vis[a[tt]]) update(vis[a[tt]] , -a[tt]) ;
                vis[a[tt]] = tt ;
                update(vis[a[tt]] , a[tt]) ;
            }
            ans[q[i].id] = ask(q[i].r) - ask(q[i].l - 1) ;
        }
        for(int i = 1 ;i <= m ;i ++)
             printf("%lld
    " ,ans[i]) ;
    	return 0 ;
    }
     
    
    每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。
  • 相关阅读:
    WSP部署错误—SharePoint管理框架中的对象“SPSolutionLanguagePack Name=0”依赖其他不存在的对象
    Elevate Permissions To Modify User Profile
    Error with Stsadm CommandObject reference not set to an instance of an object
    ASP.NET MVC3添加Controller时没有Scaffolding options
    测试使用Windows Live Writer写日志
    配置TFS 2010出现错误—SQL Server 登录的安全标识符(SID)与某个指定的域或工作组帐户冲突
    使用ADO.NET DbContext Generator出现错误—Unable to locate file
    CSS
    HTML DIV标签
    数据库
  • 原文地址:https://www.cnblogs.com/spnooyseed/p/12870904.html
Copyright © 2011-2022 走看看