zoukankan      html  css  js  c++  java
  • Mango DS Traning #49 ---线段树3 解题手记

    Training address: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=38994#overview

    B.Xenia and Bit Operations ----Codeforces 339D

    线段树大水题。。每个节点维护一个flag,flag=1表示此时应与其兄弟节点做或(|)操作,flag=2表示做异或(^)操作,然后pushup...

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define N 140010
    
    struct node
    {
        int sum,flag;
    }tree[4*N];
    
    int two_n(int mi)
    {
        int i;
        int res = 1;
        for(i=1;i<=mi;i++)
        {
            res *= 2;
        }
        return res;
    }
    
    int a[N];
    
    void pushup(int rt)
    {
        if(tree[2*rt].flag == 1)
        {
            tree[rt].sum = tree[2*rt].sum | tree[2*rt+1].sum;
            tree[rt].flag = 2;
        }
        else
        {
            tree[rt].sum = tree[2*rt].sum ^ tree[2*rt+1].sum;
            tree[rt].flag = 1;
        }
    }
    
    void build(int l,int r,int rt)
    {
        if(l == r)
        {
            tree[rt].sum = a[l];
            tree[rt].flag = 1;
            return;
        }
        int mid = (l+r)/2;
        build(l,mid,2*rt);
        build(mid+1,r,2*rt+1);
        pushup(rt);
    }
    
    void update(int l,int r,int pos,int val,int rt)
    {
        if(l == r)
        {
            tree[rt].sum = val;
            tree[rt].flag = 1;
            return;
        }
        int mid = (l+r)/2;
        if(pos<=mid)
            update(l,mid,pos,val,2*rt);
        else
            update(mid+1,r,pos,val,2*rt+1);
        pushup(rt);
    }
    
    int main()
    {
        int n,m;
        int i,pos,val;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            int ken = two_n(n);
            for(i=1;i<=ken;i++)
            {
                scanf("%d",&a[i]);
            }
            build(1,ken,1);
            for(i=0;i<m;i++)
            {
                scanf("%d%d",&pos,&val);
                update(1,ken,pos,val,1);
                printf("%d
    ",tree[1].sum);
            }
        }
        return 0;
    }
    View Code

    D.Copying Data ----Codeforces 292E

    这题初看像线段树题,结果就是线段树题。怎么做树,维护哪些值呢? 开始想歪了,参照了别人的报告,于是知道,可以维护stx,sty值,这些值只在叶子节点上表现出来,因为只查叶子节点,不查区间,stx记录这个节点有没有被copy成a数组中的元素,stx == 0则代表还没被a给拷贝过来,否则,stx记录的是从x点开始拷贝k个的那个x值,等会后面要用到。sty则是随stx,stx要更新时,sty也要更新,sty初始为0,这时的sty为拷贝从b的y个位置开始的那个y值,总之,即输入x,y,k,stx记录x,sty记录y。最后查询pos节点,如果其stx或sty为0,说明这个节点还没有受到“侵染“,保持原来的b数组中的值,所以输出b[pos]。否则,已经收到”侵染“,输出a[pos-sty+stx],即从a中去与距离相等的元素,距离就是那个pos-sty,这时知道sty的作用了吧。。

    代码:

    /*3900KB 280ms*/
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define N 100010
    
    int a[N],b[N];
    int n,m;
    
    struct node
    {
        int stx,sty;
    }tree[4*N];
    
    void build(int l,int r,int rt)
    {
        tree[rt].stx = tree[rt].sty = 0;
        if(l == r)
        {
            return;
        }
        int mid = (l+r)/2;
        build(l,mid,2*rt);
        build(mid+1,r,2*rt+1);
    }
    
    void pushdown(int rt)
    {
        if(tree[rt].stx)
        {
            tree[2*rt].stx = tree[2*rt+1].stx = tree[rt].stx;
            tree[2*rt].sty = tree[2*rt+1].sty = tree[rt].sty;
            tree[rt].stx = tree[rt].sty = 0;
        }
    }
    void change(int l,int r,int aa,int bb,int stx,int sty,int rt)
    {
        if(aa<=l&&bb>=r)
        {
            tree[rt].stx = stx;
            tree[rt].sty = sty;
            return;
        }
        pushdown(rt);
        int mid = (l+r)/2;
        if(bb<=mid)
            change(l,mid,aa,bb,stx,sty,2*rt);
        else if(aa>mid)
            change(mid+1,r,aa,bb,stx,sty,2*rt+1);
        else
        {
            change(l,mid,aa,bb,stx,sty,2*rt);
            change(mid+1,r,aa,bb,stx,sty,2*rt+1);
        }
    }
    
    node query(int l,int r,int pos,int rt)
    {
        if(l == r)
        {
            return tree[rt];
        }
        pushdown(rt);
        int mid = (l+r)/2;
        if(pos<=mid)
            return query(l,mid,pos,2*rt);
        return query(mid+1,r,pos,2*rt+1);
    }
    
    int main()
    {
    
        int i;
        int x,y,k,pos;
        int op;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            for(i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
            }
            for(i=1;i<=n;i++)
            {
                scanf("%d",&b[i]);
            }
            build(1,n,1);
            for(i=0;i<m;i++)
            {
                scanf("%d",&op);
                if(op == 1)
                {
                    scanf("%d%d%d",&x,&y,&k);
                    change(1,n,y,y+k-1,x,y,1);
                }
                else
                {
                    scanf("%d",&pos);
                    node ans = query(1,n,pos,1);
                    if(ans.stx == 0)
                    {
                        printf("%d
    ",b[pos]);
                    }
                    else
                    {
                        printf("%d
    ",a[pos-ans.sty+ans.stx]);
                    }
                }
            }
        }
        return 0;
    }
    View Code

    E.Circular RMQ ---Codeforces 52C

    也是很简单的一道线段树,纯当练手了,还是那样维护,只不过可能换成两个区间查询和加值罢了。。还有值得一提的输入方式,因为比较坑爹的是输入不定,所以借鉴了别人的stringstream 方法,核心代码如下:

    gets(buffer);
    stringstream ss(buffer);
    ss>>aa>>bb;

    具体实现在下面。。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <string>
    #include <utility>
    #include <cstdlib>
    #include <sstream>
    using namespace std;
    #define N 200010
    
    struct node
    {
        lll mini;
        lll addmark;
    }tree[4*N];
    
    int n,m;
    lll a[N];
    
    void pushup(int rt)
    {
        tree[rt].mini = min(tree[2*rt].mini,tree[2*rt+1].mini);
    }
    
    void build(int l,int r,int rt)
    {
        tree[rt].addmark = 0;
        if(l == r)
        {
            tree[rt].mini = a[l];
            return;
        }
        int mid = (l+r)/2;
        build(l,mid,2*rt);
        build(mid+1,r,2*rt+1);
        pushup(rt);
    }
    
    void pushdown(int rt)
    {
        if(tree[rt].addmark)
        {
            tree[2*rt].mini += tree[rt].addmark;
            tree[2*rt+1].mini += tree[rt].addmark;
            tree[2*rt].addmark += tree[rt].addmark;
            tree[2*rt+1].addmark += tree[rt].addmark;
            tree[rt].addmark = 0;
        }
    }
    
    void add(int l,int r,int aa,int bb,int val,int rt)
    {
        if(aa>r||bb<l)
            return;
        if(aa<=l&&bb>=r)
        {
            tree[rt].mini += val;
            tree[rt].addmark += val;
            return;
        }
        pushdown(rt);
        int mid = (l+r)/2;
        if(aa<=mid)
            add(l,mid,aa,bb,val,2*rt);
        if(bb>mid)
            add(mid+1,r,aa,bb,val,2*rt+1);
        pushup(rt);
    }
    
    lll query(int l,int r,int aa,int bb,int rt)
    {    
        if(aa>r||bb<l)
            return (lll)1e17;
        if(aa<=l&&bb>=r)
        {
            return tree[rt].mini;
        }
        pushdown(rt);
        int mid = (l+r)/2;
        if(bb<=mid)
            return query(l,mid,aa,bb,2*rt);
        else if(aa>mid)
            return query(mid+1,r,aa,bb,2*rt+1);
        else
        {
            return min(query(l,mid,aa,bb,2*rt),query(mid+1,r,aa,bb,2*rt+1));
        }
    }
    
    char buffer[400000];
    
    int main()
    {
        int i,aa,bb;
        lll val,ans;
        while(scanf("%d",&n)!=EOF)
        {
            for(i=1;i<=n;i++)
            {
                scanf("%I64d",&a[i]);
            }
            build(1,n,1);
            scanf("%d",&m);
            gets(buffer); 
            for(i=0;i<m;i++)
            {
                gets(buffer);
                stringstream ss(buffer);
                ss>>aa>>bb;
                aa++,bb++;
                if(ss>>val)
                {
                    if(aa<=bb)
                    {
                        add(1,n,aa,bb,val,1);
                    }
                    else
                    {
                        add(1,n,aa,n,val,1);
                        add(1,n,1,bb,val,1);
                    }
                }
                else
                {
                    if(aa<=bb)
                        ans = query(1,n,aa,bb,1);
                    else
                    {
                        lll res = query(1,n,aa,n,1);
                        ans = query(1,n,1,bb,1);
                        ans = min(ans,res);
                    }
                    printf("%I64d
    ",ans);
                }
            }
        }
        return 0;
    }
    View Code

    H.Vessels ---Codeforces 371D

    这道题我原来出的时候记得是线段树,但是后来看别人的代码,没看见一个用线段树写的,,我去。原来硬搞也能过。。难点是想到,。下面放我借鉴别人的代码吧:

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define N 200010
    
    int cap[N],jp[N],a[N];
    
    int main()
    {
        int n,m;
        int i,j;
        int op,pos,val;
        int st;
        while(scanf("%d",&n)!=EOF)
        {
            memset(cap,0,sizeof(cap));
            for(i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
                jp[i] = i;
            }
            scanf("%d",&m);
            for(i=0;i<m;i++)
            {
                scanf("%d",&op);
                if(op == 1)
                {
                    scanf("%d%d",&pos,&val);
                    st = jp[pos];
                    while(cap[st]+val>=a[st]&&st<=n)
                    {
                        val -= (a[st]-cap[st]);
                        cap[st] = a[st];
                        st++;
                    }
                    if(st<=n)
                        cap[st] += val;
                    for(j=jp[pos];j<st;j++)
                    {
                        jp[j] = st;
                    }
                    jp[pos] = st;
                }
                else
                {
                    scanf("%d",&pos);
                    printf("%d
    ",cap[pos]);
                }
            }
        }
        return 0;
    }
    View Code

    作者:whatbeg
    出处1:http://whatbeg.com/
    出处2:http://www.cnblogs.com/whatbeg/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
    更多精彩文章抢先看?详见我的独立博客: whatbeg.com

  • 相关阅读:
    火狐下,td 的 bug;
    在centos6.3用yum安装redis
    Linux系统下修改环境变量PATH路径的三种方法
    网络文件常常提到类似"./run.sh"的数据,这个命令的意义是什么?
    DataGridView的自定义列排序
    【Linux】linux常用基本命令
    用户名 不在 sudoers文件中,此事将被报告。(转)
    将XML文件中的内容转换为Json对象
    C# 加载xml文档文件及加载xml字符串
    增加不存在的列
  • 原文地址:https://www.cnblogs.com/whatbeg/p/3492944.html
Copyright © 2011-2022 走看看