zoukankan      html  css  js  c++  java
  • Ocean的礼物(线段树单点修改)

    题目链接http://oj.ismdeep.com/contest/Problem?id=1284&pid=0

    A: Ocean的礼物

    Time Limit: 5 s      Memory Limit: 128 MB     
    My Status

    Problem Description

           皇家理工存在一段很神奇的路段,这段路由nn 个格子组成,每个格子都有一个数字,你可以走这段路的任意一段。这段路的神奇之处就在于,如果你所处的这个格子数字和你经过的前一个格子数字不相同的话,你就可以获得一个礼物(初始一定可以获得礼物)。现在Ocean想知道,给定任意路段的左边界和右边界,问若走这段路可以获得多少礼物。不过幸运的是,Ocean很快就解决了,并且获得了大量的礼物。玩的十分开心。但是有一天,这段路神奇的发生了改变。它不但会给你礼物。它还可能随时的改变其任意某处的格子上的数字。这下Ocean可就犯愁了,他想知道任意一段路可以获得的礼物是多少。聪明的你可以帮下他吗?

    Input

    第一行输入一个整数nn ,代表格子数。(1n106)(1≤n≤106)

    第二行输入nn 个整数xx 。(1x108)(1≤x≤108)

    第三行输入一个整数mm ,代表mm 次操作。(1m2105)(1≤m≤2∗105)

    接下来第四行到3+m3+m 行每行33 个数opxyop,x,y 。

    op=1op=1 则把xx 处的数修改为yy 。(1xn,1y108)(1≤x≤n,1≤y≤108)

    op=2op=2 ,询问区间[x,y][x,y] 内可以获得的礼物数。(1xyn)(1≤x≤y≤n)

    Output

    对于每个询问输出一个整数,代表可以获得的礼物数

    Sample Input

    6
    1 2 3 4 5 6
    4
    2 1 6
    1 2 3
    2 2 3
    2 3 4
    

    Sample Output

    6
    1
    2
    

    Hint

    解题思路:做这题之前表示还没看过线段树,后来比赛完了,随便看了一篇关于线段树区间修改的文章,感觉可以运用到这题,然后我就硬生生把这题单点修改的问题当做区间修改来写了,就是每次修改点的时候判断与前面那个数是否一致,后面那个数是否一致,原来那个数,与前面那个数是否一致,与后面那个数是否一致,一共是16种情况,贼复杂,没办法还不太会用,还好时间限制比较松,运行了2000ms,AC了,先看下我的垃圾代码吧。。。下面再上正确代码。

    具体看代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt*2+1
    #define pushup(rt) t[rt]=t[rt*2]+t[rt*2+1]
    typedef long long ll;
    const ll mod=1000000007;
    const ll maxn=1000007;
    int k=1;
    ll t[maxn*4],lazy[maxn*4],a[maxn*4],num[maxn];
    
    void build(int l,int r,int rt)
    {
        lazy[rt] = 0;
        if(l==r)
        {
            t[rt]=a[k++];
            //scanf("%lld",&t[rt]);
            return ;
        }
        int m = (l+r)/2;
        build(lson);
        build(rson);
        pushup(rt);
    }
    void pushdown(int l,int r,int rt)
    {
        if(lazy[rt])
        {
            lazy[rt*2] += lazy[rt];
            lazy[rt*2+1] += lazy[rt];
            t[rt*2] += l*lazy[rt];
            t[rt*2+1] += r*lazy[rt];
            lazy[rt] = 0;
        }
    }
    void update(int L,int R,int C,int l,int r,int rt)
    {
        if(L<=l&&r<=R)
        {
            t[rt] += (r-l+1)*C;
            lazy[rt] += C;
            return ;
        }
        int m = (l+r)/2;
        pushdown(m-l+1,r-m,rt);
        if(L<=m)
            update(L,R,C,lson);
        if(R>m)
             update(L,R,C,rson);
        pushup(rt);
    }
    ll query(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&r<=R)
            return t[rt];
        int m = (l+r)/2;
        pushdown(m-l+1,r-m,rt);
        ll ans = 0;
        if(L<=m)
            ans += query(L,R,lson);
        if(R>m)
            ans += query(L,R,rson);
        return ans;
    }
    
    int n,q,op,x;
    ll y;
    
    int main()
    {
        while(scanf("%d",&n)!=EOF)
        {
            a[1]=1;
            for(int i=1;i<=n;i++)
            {
                scanf("%lld",&num[i]);
                if(i>1&&num[i]!=num[i-1])
                    a[i]=1;
                if(i>1&&num[i]==num[i-1])
                    a[i]=0;
            }
            num[0]=num[n+1]=0;
            build(1,n,1);
            scanf("%d",&q);
            while(q--)
            {
                scanf("%d",&op);
                scanf("%d%lld",&x,&y);
                if(op==1)
                {
                    if(num[x]!=num[x-1]&&num[x]!=num[x+1])
                    {
                        if(y!=num[x-1]&&y!=num[x+1])
                            continue;
                        else if(y==num[x-1]&&y!=num[x+1])
                            update(x,x,-1,1,n,1);
                        else if(y!=num[x-1]&&y==num[x+1])
                            update(x+1,x+1,-1,1,n,1);
                        else
                            update(x,x+1,-1,1,n,1);
                    }
                    else if(num[x]==num[x-1]&&num[x]!=num[x+1])
                    {
                        if(y!=num[x-1]&&y!=num[x+1])
                            update(x,x,1,1,n,1);
                        else if(y==num[x-1]&&y!=num[x+1])
                            continue;
                        else if(y!=num[x-1]&&y==num[x+1])
                        {
                            update(x,x,1,1,n,1);
                            update(x+1,x+1,-1,1,n,1);
                        }
                        else
                            update(x+1,x+1,-1,1,n,1);
                    }
                    else if(num[x]!=num[x-1]&&num[x]==num[x+1])
                    {
                        if(y!=num[x-1]&&y!=num[x+1])
                            update(x+1,x+1,1,1,n,1);
                        else if(y==num[x-1]&&y!=num[x+1])
                        {
                            update(x,x,-1,1,n,1);
                            update(x+1,x+1,1,1,n,1);
                        }
                        else if(y!=num[x-1]&&y==num[x+1])
                            continue;
                        else
                            update(x,x,-1,1,n,1);
                    }
                    else
                    {
                        if(y!=num[x-1]&&y!=num[x+1])
                            update(x,x+1,1,1,n,1);
                        else if(y==num[x-1]&&y!=num[x+1])
                            update(x+1,x+1,1,1,n,1);
                        else if(y!=num[x-1]&&y==num[x+1])
                            update(x,x,1,1,n,1);
                        else
                            continue;
                    }
                    num[x]=y;
                }
                else
                {
                    if(num[x]==num[x-1])
                        printf("%lld
    ",query(x,y,1,n,1)+1);
                    else
                        printf("%lld
    ",query(x,y,1,n,1));
                }
            }
        }
        return 0;
    }

    正确思路:构建线段树时,一个节点保存三个信息,所在区间的不同的线段个数,区间的左边界和右 边界,合并区间时,比较左子区间的右边界和右子区间的左边界,若相等,就是两个区间 的不相同的线段树个数相加减一。

    正确代码:

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <cstdlib>
    #include <iomanip>
    #include <cmath>
    #include <cassert>
    #include <ctime>
    #include <map>
    #include <set>
    using namespace std;
    #pragma comment(linker, "/stck:1024000000,1024000000")
    #pragma GCC diagnostic error "-std=c++11"
    #define lowbit(x) (x&(-x))
    #define max(x,y) (x>=y?x:y)
    #define min(x,y) (x<=y?x:y)
    #define MAX 100000000000000000
    #define MOD 1000000007
    #define esp 1e-9
    #define pi acos(-1.0)
    #define ei exp(1)
    #define PI 3.1415926535897932384626433832
    #define ios() ios::sync_with_stdio(true)
    #define INF 0x3f3f3f3f
    #define mem(a) (memset(a,0,sizeof(a)))
    typedef long long ll;
    const int maxn=1000006;
    int tree[maxn<<2][3];
    int n,m,x,y,op;
    void pushup(int root)
    {
        tree[root][2]=tree[root<<1][2]+tree[root<<1|1][2];
        tree[root][0]=tree[root<<1][0];
        tree[root][1]=tree[root<<1|1][1];
        if(tree[root<<1][1]==tree[root<<1|1][0]) tree[root][2]--;
        //合并区间时,比较左子区间的右边界和右子区间的左边界,若相
        //等,就是两个区间 的不相同的线段树个数相加减一
    }
    void build(int l,int r,int root)
    {
        if(l==r)
        {
            scanf("%d",&tree[root][0]);   //tree[root][0]区间的左边界
            tree[root][1]=tree[root][0];  //tree[root][1]区间的右边界
            tree[root][2]=1;    //tree[root][2]所在区间不同的线段个数
            return ;
        }
        int mid=l+r>>1;
        build(l,mid,root<<1);
        build(mid+1,r,root<<1|1);
        pushup(root);
    }
    void update(int pos,int val,int l,int r,int root)
    {
        if(l==r)
        {
            tree[root][0]=tree[root][1]=val;
            return ;
        }
        int mid=l+r>>1;
        if(pos<=mid) update(pos,val,l,mid,root<<1);
        else update(pos,val,mid+1,r,root<<1|1);
        pushup(root);
    }
    int query(int L,int R,int l,int r,int root)
    {
        if(L<=l && R>=r) return tree[root][2];
        int ans=0,mid=l+r>>1;
        if(L<=mid) ans+=query(L,R,l,mid,root<<1);
        if(R>mid) ans+=query(L,R,mid+1,r,root<<1|1);
        if(L<=mid && R>mid && tree[root<<1][1]==tree[root<<1|1][0]) ans--;
        return ans;
    }
    int main()
    {
        scanf("%d",&n);
        build(1,n,1);
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d%d%d",&op,&x,&y);
            if(op==1) update(x,y,1,n,1);
            else printf("%d
    ",query(x,y,1,n,1));
        }
        return 0;
    }
  • 相关阅读:
    shell 自动登录 上传 下载
    用例设计----PICT&Allpairs
    已有实例 Oracle 下新增实例
    【原创】安卓兼容性测试
    【原创】某版本性能测试
    【原创】Jmeter正则表达式提取json中多个关联值
    【转】四种常见的 POST 提交数据方式
    rfw使用接口库测试--FAIL : UnicodeEncodeError: 'ascii' codec can't encode characters in position
    【原创】Robotframework 简介
    java学习笔记_内存分析
  • 原文地址:https://www.cnblogs.com/zjl192628928/p/9473191.html
Copyright © 2011-2022 走看看