【LuoguP3616】富金森林公园-线段树

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Maxwei_wzj/article/details/83315737

测试地址:富金森林公园
做法: 本题需要用到线段树。
一道好题,不看题解乍一下真的不知道怎么做…
我们考虑直接维护水面在高度 i i 时能看见的连续段数 c n t ( i ) cnt(i) ,考虑一块石头高度的增减对 c n t cnt 的影响。为了讨论方便,我们把修改操作都看成是,先把石头高度降到最低,再把石头高度升到新的高度,这样只用考虑两个过程就可以了,并且我们发现这两个过程产生的贡献完全相反,因此我们现在只考虑升的过程就好了。
考虑这块石头相邻的两块石头高度 a , b a,b ,假定 a < b a<b ,那么在当前石头升到高度 a \le a 这一段,水面高度在这一段时的答案应该 1 -1 ,因为两块被连接成一块;而在高度从 a a 升到 b b 的这一段,水面高度为这一段时的答案不发生变化,因为原来是一段,现在还是一段;当升到比 b b 高时,水面高度为这一段时的答案会 + 1 +1 ,因为原来这里没有石头,现在多出来了一块。这样讨论之后,我们发现用线段树进行区间修改就能完成这一题了,时间复杂度为 O ( n log n ) O(n\log n)
以下是本人代码:

#include <bits/stdc++.h>
using namespace std;
int n,m,tot,a[200010]={0},h[200010],op[200010],opx[200010],opid[200010];
int seg[2000010]={0},tag[2000010]={0};
struct forsort
{
    bool type;
    int id,val;
}f[400010];

bool cmp(forsort a,forsort b)
{
    return a.val<b.val;
}

void pushdown(int no,int l,int r)
{
    int mid=(l+r)>>1;
    if (tag[no]!=0)
    {
        tag[no<<1]+=tag[no],tag[no<<1|1]+=tag[no];
        seg[no<<1]+=tag[no]*(mid-l+1);
        seg[no<<1|1]+=tag[no]*(r-mid);
        tag[no]=0;
    }
}

void pushup(int no)
{
    seg[no]=seg[no<<1]+seg[no<<1|1];
}

void segmodify(int no,int l,int r,int s,int t,int d)
{
    if (l>=s&&r<=t)
    {
        seg[no]+=(r-l+1)*d;
        tag[no]+=d;
        return;
    }
    int mid=(l+r)>>1;
    pushdown(no,l,r);
    if (s<=mid) segmodify(no<<1,l,mid,s,t,d);
    if (t>mid) segmodify(no<<1|1,mid+1,r,s,t,d);
    pushup(no);
}

int query(int no,int l,int r,int x)
{
    if (l==r) return seg[no];
    int mid=(l+r)>>1;
    pushdown(no,l,r);
    if (x<=mid) return query(no<<1,l,mid,x);
    else return query(no<<1|1,mid+1,r,x);
}

void modify(int id,int type)
{
    if (min(a[id],min(a[id-1],a[id+1]))>0)
        segmodify(1,1,tot,1,min(a[id],min(a[id-1],a[id+1])),-type);
    if (a[id]>max(a[id-1],a[id+1]))
        segmodify(1,1,tot,max(a[id-1],a[id+1])+1,a[id],type);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&f[i].val);
        f[i].type=0,f[i].id=i;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&op[i]);
        if (op[i]==1) scanf("%d",&f[n+i].val);
        else scanf("%d%d",&opid[i],&f[n+i].val);
        f[n+i].type=1,f[n+i].id=i;
    }
    
    sort(f+1,f+n+m+1,cmp);
    tot=0;
    for(int i=1;i<=n+m;i++)
    {
        if (i==1||f[i].val!=f[i-1].val)
            tot++;
        if (!f[i].type) h[f[i].id]=tot;
        else opx[f[i].id]=tot;
    }
    
    for(int i=1;i<=n;i++)
    {
        a[i]=h[i];
        modify(i,1);
    }
    for(int i=1;i<=m;i++)
    {
        if (op[i]==1) printf("%d\n",query(1,1,tot,opx[i]));
        else
        {
            modify(opid[i],-1);
            a[opid[i]]=opx[i];
            modify(opid[i],1);
        }
    }
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Maxwei_wzj/article/details/83315737