zoukankan      html  css  js  c++  java
  • Luogu P3616 富金森林公园

    树状数组+离散化+转化

      一道树状数组好题!我们先来一发弱化版:如果只查询有多少个石头,怎么做?很简单,我们需要考虑权值树状数组,先离散化(因为我们只需要考虑高矮关系),如何离散化?考虑离线,将可能改变的值都存下来,离散化一下。每次的查询通过二分来找到对应的离散化之后的值。之后就是权值树状数组的常规操作了,将之前的贡献减去,将新来的贡献加上。但是,这道题问的是有多少个连续的部分。考虑去重,如果一个点比她左边的一个点海拔要低,那么就会重复计数,那么就应该在她所对应的权值上减去1,同理,如果她比她右边的点海拔低,那么也要减1.最后查询一个数x,就是查询去掉[1,x-1]的影响后的值,可以用前缀和实现。
    注意特判边界:1、n!!!!!!!!!!!!

    code:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<queue>
    #include<cstring>
    #include<vector>
    #include<stack>
    #include<algorithm>
    #define int long long 
    using namespace std;
    const int maxn=2000006;
    #define half (l+r)>>1
    struct hzw
    {
        int rhi,hi;
        int id;
    }s[maxn];
    struct zmd
    {
        int id;
        int x,y;
    }q[maxn];
    inline bool cmp1(hzw a,hzw b)
    {
        return a.rhi<b.rhi;
    }
    inline bool cmp2(hzw a,hzw b)
    {
        return a.id<b.id;
    }
    int n,m,tot,val[maxn];
    inline int search(int k)
    {
        int l=1,r=tot+1,ans=1e9;
        while (l<=r)
        {
            int mid=half;
            if (s[mid].rhi>=k)
            {
                r=mid-1;
                ans=min(ans,s[mid].hi);
            }
            else l=mid+1;
        }
        if (ans==1e9) return tot+1;
        return ans;
    } 
    inline void update(int x,int k)
    {
    	if (!x) return;
    	if (x>tot) return;
        for (int i=x;i<=tot;i+=(i&(-i)))
        {
            val[i]+=k;
        }
    }
    inline int query(int x)
    {
        int ans=0;
        if (!x) return 0;
        if (x>tot) x=tot;
        for (int i=x;i>0;i-=i&(-i))
        {
            ans+=val[i];
        }
        return ans;
    }
    signed main()
    {
        cin>>n>>m;
        for (int i=1;i<=n;++i)
        {
            scanf("%lld",&s[i].rhi);
            s[i].id=i;
        }
        tot=n;
        for (int i=1;i<=m;++i)
        {
            scanf("%lld",&q[i].id);
            if (q[i].id==1) scanf("%lld",&q[i].x);
            else 
            {
                scanf("%lld%lld",&q[i].x,&q[i].y);
                s[++tot].id=tot,
                s[tot].rhi=q[i].y;
            }
        }
        sort(s+1,s+1+tot,cmp1);
        for (int i=1;i<=tot;++i)
        {
            if (s[i].rhi==s[i-1].rhi) s[i].hi=s[i-1].hi;
            else s[i].hi=s[i-1].hi+1;
        }
        for (int i=1;i<=m;++i)
        {
            if (q[i].id==2) continue;
            q[i].x=search(q[i].x);
        }
        sort(s+1,s+1+tot,cmp2);
        int cnt=n;
        for (int i=1;i<=n;++i) 
    	{
    		update(s[i].hi,1);
    		update(min(s[i].hi,s[i-1].hi),-1);
    	}
        for (int i=1;i<=m;++i)
        {
            if (q[i].id==1)
            {
                printf("%lld
    ",query(tot)-query(q[i].x-1));
                continue;
            }
            else 
            {
                cnt++;
                update(s[q[i].x].hi,-1);
                if (q[i].x!=1)update(min(s[q[i].x].hi,s[q[i].x-1].hi),1);
                if (q[i].x!=n)update(min(s[q[i].x].hi,s[q[i].x+1].hi),1);
                s[q[i].x].hi=s[cnt].hi;
                update(s[q[i].x].hi,1);
    	    if (q[i].x!=1)update(min(s[q[i].x].hi,s[q[i].x-1].hi),-1);
    	    if (q[i].x!=n)update(min(s[q[i].x].hi,s[q[i].x+1].hi),-1);
            }
        }
        return 0;  
    }
    

    总结:

    1、类似这样有关于值的大小比较类问题要考虑用权值版,利用巧妙地离散化解决问题。
    2、这种会重复计算的要考虑怎么去重;
    3、注意边界

  • 相关阅读:
    每日一题计划
    acm新手刷题攻略之poj
    Swift几行代码设置UIcollectionView的section底色,圆角
    简单几行代码设置UIcollectionView底色、section背景底色、背景色、背景阴影、背景圆角,支持CollectionView内容左对齐、居中对齐、右对齐、右对齐且右开始排序,支持底色点击反馈
    iOS12 EachNavigationBar导航栏操作出现黑边解决办法
    EachNavigationBar 导航栏颜色与给定颜色不相同设定
    详解冒泡排序法
    递归的简单用法
    判断一个整数是否为素数(质数)
    tcp黏包与拆包
  • 原文地址:https://www.cnblogs.com/bullshit/p/9712297.html
Copyright © 2011-2022 走看看