• 线段树脑洞题 P2184 贪婪大陆


    说实话这道题还是非常好的,因为他给我们提供了一种非常巧妙的想法——差分!

    当时我看到这道题的时候我就一直在想我应该如何做去维护当前区间的一些信息,然后就这样想啊想,发现越想越不对,越想越爆炸!然后我结合以前做的几道线段树题,我想如果真的有这么难的话,这道题怎么可能才是一道蓝题,事实证明我确实是想错了!

    这道题的思路也是非常的简单啊!我们只需要每次埋地雷的时候,我们只需要标记一下当前区间的开头和结尾,我们查的时候,我们只需要查1到当前区间结尾中包含了多少个开头(一个开头代表了一种地雷)然后我们查1到当前区间前一个位置包含了多少个结尾(一个结尾代表我们一种地雷埋完了,就是我们看前面有几种地雷被埋完了!)然后把这个做差,我们就可以知道有多少种地雷是出现在当前区间中,然后这道题就成功的被我们转化成了一个单点修改,区间查询的线段树。

    如果上面的东西还是没有看懂的话,大家可以结合下面这个示意图理解一下:

    我们这里假设红色的三角形为开始标记(有可能多个开始标记在一起,我们只需要记个数就可以了!)绿色的为结束标记,那么我们可以发现我们查询区间前面那一段的绿色标记为两个,表明在到查询区间之前已经有两种地雷埋完了,而包括查询区间在内的前面的所有的开始标记,减去结束标记就是我们要知道的在查询区间内出现的地雷的种数!

    相信大家应该都懂了!

    AC code:

    #include<bits/stdc++.h>
    using namespace std;
    struct sd{
        int l,r,son[2],sta,end;
    }node[1000004];
    int root,n,m,cnt;
    void Buildtree(int &k,int l,int r)
    {
        ++cnt;k=cnt;node[k].l=l;node[k].r=r;
        if(l==r) return;
        else
        {
            int mid=(l+r)/2;
            Buildtree(node[k].son[0],l,mid);
            Buildtree(node[k].son[1],mid+1,r);
        }
    }
    void modify_sta(int k,int pos)
    {
        if(node[k].l==node[k].r) node[k].sta++;
        else
        {
            int mid=(node[k].l+node[k].r)/2;
            if(pos<=mid) modify_sta(node[k].son[0],pos);
            else modify_sta(node[k].son[1],pos);
            node[k].sta=node[node[k].son[0]].sta+node[node[k].son[1]].sta;
        }
    }
    void modify_end(int k,int pos)
    {
        if(node[k].l==node[k].r) node[k].end++;
        else
        {
            int mid=(node[k].l+node[k].r)/2;
            if(pos<=mid) modify_end(node[k].son[0],pos);
            else modify_end(node[k].son[1],pos);
            node[k].end=node[node[k].son[0]].end+node[node[k].son[1]].end;
        }
    }
    int query_end(int k,int l,int r)
    {
        if(node[k].l==l&&node[k].r==r) return node[k].end;
        else
        {
            int mid=(node[k].l+node[k].r)/2;
            if(r<=mid) return query_end(node[k].son[0],l,r);
            else if(l>mid) return query_end(node[k].son[1],l,r);
            else return query_end(node[k].son[0],l,mid)+query_end(node[k].son[1],mid+1,r);
        }
    }
    int query_sta(int k,int l,int r)
    {
        if(node[k].l==l&&node[k].r==r) return node[k].sta;
        else
        {
            int mid=(node[k].l+node[k].r)/2;
            if(r<=mid) return query_sta(node[k].son[0],l,r);
            else if(l>mid) return query_sta(node[k].son[1],l,r);
            else return query_sta(node[k].son[0],l,mid)+query_sta(node[k].son[1],mid+1,r);
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        int a,b,c;
        Buildtree(root,1,n);
        for(int i=1;i<=m;++i)
        {
            scanf("%d%d%d",&a,&b,&c);
            if(a==1){modify_sta(root,b);modify_end(root,c);}
            if(a==2){printf("%d
    ",query_sta(root,1,c)-query_end(root,1,b-1));}
        }
    }
    

    By njc

  • 相关阅读:
    js实现深拷贝的5种方式
    react中Context的使用
    react中link参数传递以及url乱码解决
    js中forEach结束循环
    javaScript函数和方法的区别
    将逻辑运算字符串转化为逻辑运算进行运算
    redux的使用流程
    react类型检查
    for..in,for..of 和forEach的区别
    JavaScript基础知识(JSON、Function对象、原型、引用类型)
  • 原文地址:https://www.cnblogs.com/mudrobot/p/13329084.html
Copyright © 2020-2023  润新知