• luoguP2184 贪婪大陆 题解(树状数组)


    P2184 贪婪大陆  题目

    其实很容易理解就是询问一段区间内有多少段不同的区间

    然后再仔细思索一下会发现:

    1.只要一个区间的开头在一个节点i的左边,那么这个区间包含在区间1~i中。

    2.只要一个区间的尾部在一个节点j的左边,那么这个区间肯定不属于j之后的所有区间

    这时候就不难想到用两个树状数组维护:

    第一个:维护节点i之前有多少个区间的开头

    第二个:维护节点j之前有多少个区间的结尾

    不难证明拿sum[i]-sum[j]得到的就是i~j中间地雷的个数(手动模拟一波就一清二楚了)

     #include<iostream>
        #include<cstdlib>
        #include<cstdio>
        #include<cmath>
        #include<cstring>
        #include<iomanip>
        #include<algorithm>
        #include<stack>
        #include<queue>
        #define lst long long
        #define rg register
        #define N 100050
        using namespace std;
        int n,m;
        lst ans;
        int tou[N],wei[N];//tou存前面有多少个区间的开始,以下简称头部树状数组
                          //wei存前面有多少个区间的尾部,以下简称尾部树状数组
                          //类似于前缀和
        inline int read()//读入优化
        {
            rg int s=0,m=1;rg char ch=getchar();
            while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
            if(ch=='-')m=-1,ch=getchar();
            while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
            return s*m;
        }
        //以下是树状数组的板子
        inline int lowbit(rg int kk)//lowbit
        {
            return kk&(-kk);
        }
        inline void add_tou(rg int kk)//加入树状数组的头部数组
        {
            while(kk<=n)
            {
                ++tou[kk];
                kk+=lowbit(kk);
            }
        }
        inline void add_wei(rg int kk)//加入树状数组的尾部数组
        {
            while(kk<=n)
            {
                ++wei[kk];
                kk+=lowbit(kk);
            }
        }
        inline int sum_tou(rg int kk)//计算节点前有多少个区间的开始
        {
            rg int s=0;
            while(kk>0)
            {
                s+=tou[kk];
                kk-=lowbit(kk);
            }
            return s;
        }
        inline int sum_wei(rg int kk)//计算节点前有多少个区间的结束
        {
            rg int s=0;
            while(kk>0)
            {
                s+=wei[kk];
                kk-=lowbit(kk);
            }
            return s;
        }
        int main()
        {
            n=read(),m=read();//读入
            for(rg int i=1;i<=m;++i)
            {
                rg int sign=read();
                rg int x=read(),y=read();//读入
                if(sign==1)
                {
                    add_tou(x);//加入头部树状数组
                    add_wei(y);//加入尾部树状数组
                }
                else
                {
                    ans=sum_tou(y)-sum_wei(x-1);//运用已经证明的规律结题
                    printf("%d
    ",ans);
                }
            }
            return 0;
        }

    通过这道题,我们可以发现大部分的树状数组题目可以用线段树做,但也有线段树不好维护的题目,这就需要灵活的利用树状数组的技巧(虽然题解里也有线段树比较好理解的) 我自认为我的代码还是蛮好看的,只是变量有点丑,但好理解

  • 相关阅读:
    201671010456-张琼 实验三作业互评与改进
    阅读《构建之法》后的相关问题
    个人作业-软件工程实践总结
    团队作业第二次—项目选题报告
    结对第二次—文献摘要热词统计及进阶需求
    结对第一次—原型设计(文献摘要热词统计)
    第一次作业-准备篇
    个人作业——软件工程实践总结作业
    团队作业第二次—项目选题报告
    结对第二次—文献摘要热词统计及进阶需求
  • 原文地址:https://www.cnblogs.com/cjoierljl/p/8783506.html
Copyright © 2020-2023  润新知