zoukankan      html  css  js  c++  java
  • codeforces1198B Welfare State 线段树或单调栈+二分

    网址:http://codeforces.com/problemset/problem/1198/B

    题意:

    给出初始序列,规定两种操作:$1$ $p$ $x$代表把第$p$个值改成$x$,$2$ $x$代表把小于$x$的值都变成$x$,大于$x$的不变。求所有操作完成后的序列。($n ,m leq 2e5 $)。

    题解:

    一、线段树版本:

    操作即为典型的单点修改、区间修改和单点查询。lazy标记记录区间修改的值,由于$2$操作中大的$x$值一定会覆盖小的$x$值,故$lazy$标记下推时取较大值,单点修改时下推标记,由于单点修改是最高级的,所以每一次单点修改一定会清空目标叶节点的区间修改,然后单点查询时取$lazy$和叶节点值较大那个作为最终值。

    AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define MAXN 200005
    #define ls (k<<1)
    #define rs (k<<1)+1
        
    const int MAXBUF = 1 << 20;
    char buf[1<<20], *fh=NULL, *ft=NULL;
    inline char gc() 
    {
        if(fh == ft) 
        {
            int l = fread(buf, 1, MAXBUF, stdin);
            ft = (fh = buf) + l;
        }
        return *fh++;
    }
        
    inline int read() 
    {
        int x = 0;
        char c = gc();
        for(; c < '0' || c > '9'; c = gc())
            ;
        for(; c >= '0' && c <= '9'; c = gc())
            x = (x << 3) + (x << 1) + c - '0';
        return x ;
    }
    inline void _write(long long x) 
    {
        if(x > 9)
            _write(x / 10);
        putchar(x % 10 + '0');
    }
    inline void write(long long x) 
    {
        _write(x);
        //putchar('
    ');
    }
        
    struct segtree
    {
        struct node
        {
            int l,r,val,lazy;
        };
        node tr[MAXN<<2];
        void build(int l,int r,int k)
        {
            tr[k].l=l,tr[k].r=r;
            tr[k].val=tr[k].lazy=0;
            if(l==r)
                return;
            int m=(l+r)>>1;
            build(l,m,ls);
            build(m+1,r,rs);
        }
        void down(int k)
        {
            tr[ls].lazy=max(tr[k].lazy,tr[ls].lazy);
            tr[rs].lazy=max(tr[k].lazy,tr[rs].lazy);
            tr[k].lazy=0;
        }
        void update1(int pos,int k,int val)
        {
            if(tr[k].l==tr[k].r)
            {
                tr[k].lazy=0;
                tr[k].val=val;
                return;
            }
            down(k);
            int m=(tr[k].l+tr[k].r)>>1;
            if(pos<=m)
                update1(pos,ls,val);
            else
                update1(pos,rs,val);
            tr[k].val=min(tr[ls].val,tr[rs].val);
        }
        void update2(int l,int r,int k,int val)
        {
            if(l<=tr[k].l&&tr[k].r>=tr[k].r)
            {
                tr[k].lazy=max(tr[k].lazy,val);
                return;
            }
            down(k);
            int m=(tr[k].l+tr[k].r)>>1;
            if(l<=m&&val>tr[ls].val)
                update2(l,r,ls,val);
            if(r>m&&val>tr[rs].val)
                update2(l,r,rs,val);
            tr[k].val=min(tr[ls].val,tr[rs].val);
        }
        int query(int pos,int k)
        {
            if(tr[k].l==tr[k].r)
                return max(tr[k].val,tr[k].lazy);
            down(k);
            int m=(tr[k].l+tr[k].r)>>1;
            if(pos<=m)
                return query(pos,ls);
            else
                return query(pos,rs);
        }
    };
    segtree tr;
    int main()
    {
        int n,m,a,p,x;
        //scanf("%d",&n);
        n=read();
        tr.build(1,n,1);
        for(int i=1;i<=n;++i)
        {
            a=read();
            tr.update1(i,1,a);
        }
        m=read();
        for(int i=0;i<m;++i)
        {
            a=read();
            p=read();
            if(a==1)
            {
                x=read();
                tr.update1(p,1,x);
            }
            else
                tr.update2(1,n,1,p);
        }
        for(int i=1;i<=n;++i)
        {
            write(tr.query(i,1));
            putchar((i==n?'
    ':' '));
        }
        return 0;
    }
    

     二、单调栈+二分解法:

    使用单调递减栈记录区间修改操作,然后对于每一个元素,单点修改直接在原数组中修改,记录最后一次修改时间,然后在栈中二分查找它的最后一次单点修改的时间的后面最大的一个区间修改(就是其后面第一个区间修改),然后两个取最大值。

    AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN=200005;
    int sta[MAXN],top=0,num[MAXN],lstch[MAXN],add[MAXN];
    
    const int MAXBUF = 1 << 20;
    char buf[1<<20], *fh=NULL, *ft=NULL;
    inline char gc() 
    {
        if(fh == ft) 
        {
            int l = fread(buf, 1, MAXBUF, stdin);
            ft = (fh = buf) + l;
        }
        return *fh++;
    }
        
    inline void read(int &x) 
    {
        x = 0; 
        char c = gc();
        for(; c < '0' || c > '9'; c = gc())
            ;
        for(; c >= '0' && c <= '9'; c = gc())
            x = (x << 3) + (x << 1) + c - '0';
        return;
    }
    inline void _write(long long x) 
    {
        if(x > 9)
            _write(x / 10);
        putchar(x % 10 + '0');
    }
    inline void write(long long x) 
    {
        _write(x);
        //putchar('
    ');
    }
    
    int main()
    {
        int n,m,a,p,x;
        //scanf("%d",&n);
        read(n);
        for(int i=1;i<=n;++i)
            read(num[i]);
            //scanf("%d",&num[i]);
        //scanf("%d",&m);
        read(m);
        for(int i=1;i<=m;++i)
        {
            read(a);
            //scanf("%d",&a);
            read(p);
            //scanf("%d",&p);
            if(a==1)
            {
                read(x);
                //scanf("%d",&x);
                num[p]=x;
                lstch[p]=i;
            }
            else
            {
                while(top&&p>=sta[top])
                    --top;
                sta[++top]=p;
                add[top]=i;
            }
        }
        sta[++top]=0;
        add[top]=m+1;
        for(int i=1;i<=n;++i)
            num[i]=max(num[i],sta[lower_bound(add+1,add+top+1,lstch[i])-add]);
        for(int i=1;i<=n;++i)
            write(num[i]),putchar(i==n?'
    ':' ');
        return 0;
    }
    
  • 相关阅读:
    vue this,$set方法
    表格的拖拽排序功能---应用splice方法
    ES6方法的特性总结
    template functional
    scrollTop, offsetTop, pageYOffset, scrollY 的区别
    Sass @mixin 与 @include
    关于Vue中props的详解
    前端开发工具宝典
    前端js开发常用的60种工具方法
    element ui table表格里面插槽的使用方法
  • 原文地址:https://www.cnblogs.com/Aya-Uchida/p/11288763.html
Copyright © 2011-2022 走看看