zoukankan      html  css  js  c++  java
  • 2019ICPC南昌 F题 Sequence 建两个线段树

    题目链接:https://nanti.jisuanke.com/t/40258

    题意:给一个具有n个数字的序列,并且有要进行m个操作

    操作有两种:

    1.修改序列中一个数字的值

    2.给定一个区间[l,r],给出f(l,l)^f(l,l+1)...f(l,r)^...f(l+1,l+1)^...f(l+1,r)^....^f(r,r)

    其中f(l,r)=al^a(l+1)^...ar

    分析:首先是要寻找规律,不难发现,当区间l到r之间的数有偶数个时,异或和恒为0,当为奇数个时,则与左端点奇偶性相同的数为本身,不同的也直接为0

    我们考虑用线段树来进行维护,这里采用了建两个线段树的方法,学习学习。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int mod=1e9+7;
    const int maxn=1e5+7;
    const ll inf=1e18+7;
    const double pi=acos(-1);
    struct node{
        int l,r,v;
    }tree1[4*maxn],tree2[4*maxn];
    int num[maxn],num1[maxn],num2[maxn];
    int ans;
    void build1(int l,int r,int k){
        tree1[k].l=l,tree1[k].r=r;
        if(l==r){
            tree1[k].v=num1[l];
            return ;
        }
        int m=(l+r)>>1;
        build1(l,m,k*2);
        build1(m+1,r,k*2+1);
        tree1[k].v=tree1[k*2].v^tree1[k*2+1].v;
    }
    void build2(int l,int r,int k){
        tree2[k].l=l,tree2[k].r=r;
        if(l==r){
            tree2[k].v=num2[l];
            return ;
        }
        int m=(l+r)>>1;
        build2(l,m,k*2);
        build2(m+1,r,k*2+1);
        tree2[k].v=tree2[k*2].v^tree2[k*2+1].v;
    }
    void query1(int k,int x,int y){
        if(tree1[k].l>=x&&tree1[k].r<=y){
            ans^=tree1[k].v;    //cout<<111<<endl;
            return ;
        }
        int m=(tree1[k].l+tree1[k].r)/2;
        if(x<=m) query1(k*2,x,y);
        if(y>m) query1(k*2+1,x,y);
    }
    void query2(int k,int x,int y){
        if(tree2[k].l>=x&&tree2[k].r<=y){
            ans^=tree2[k].v;    //cout<<111<<endl;
            return ;
        }
        int m=(tree2[k].l+tree2[k].r)/2;
        if(x<=m) query2(k*2,x,y);
        if(y>m) query2(k*2+1,x,y);
    }
    void change1(int k,int x,int y){
        if(tree1[k].l==tree1[k].r){
            tree1[k].v=y;return;
        }
        int m=(tree1[k].l+tree1[k].r)/2;
        if(x<=m) change1(k*2,x,y);
        else change1(k*2+1,x,y);
        tree1[k].v=tree1[2*k].v^tree1[2*k+1].v;
    }
    void change2(int k,int x,int y){
        if(tree2[k].l==tree2[k].r){
            tree2[k].v=y;return;
        }
        int m=(tree2[k].l+tree2[k].r)/2;
        if(x<=m) change2(k*2,x,y);
        else change2(k*2+1,x,y);
        tree2[k].v=tree2[2*k].v^tree2[2*k+1].v;
    }
    int main(){
        int T;cin>>T;
        for(int t=1;t<=T;t++){
            int n,m;cin>>n>>m;
            for(int i=1;i<=n;i++)scanf("%d",&num[i]);
            int p=0;
            for(int i=1;i<=n;i+=2) num1[++p]=num[i];
            p=0; for(int i=2;i<=n;i+=2) num2[++p]=num[i];
            build1(1,(n+1)/2,1);build2(1,n/2,1);
            printf("Case #%d: 
    ",t);
            for(int i=0;i<m;i++){
                int opt,x,y;scanf("%d%d%d",&opt,&x,&y);
                if(opt==0){
                    if(x%2)change1(1,(x+1)/2,y);
                    else change2(1,x/2,y);
                }
                if(opt==1){
                    if((y-x)%2){
                        printf("0
    ");
                    }
                    else{
                        ans=0;
                        if(x%2){
                            query1(1,(x+1)/2,(y+1)/2);
                        }
                        else query2(1,x/2,y/2);
                        printf("%d
    ",ans);
                    }
                }
            }
        }
        return 0;
    }

    PS:实测发现线段树的一个结点用结构体会慢一些,可以直接建两个数组,左右端点可在函数里传进去

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int maxn=1e5+10;
    int dat_j[4*maxn],dat_o[4*maxn];
    int num1[maxn],num2[maxn],num[maxn];
    void build1(int a,int l,int r){
        if(l==r)    dat_j[a]=num1[l];
        else{
            int mid=(l+r)>>1;
            build1(a<<1,l,mid);
            build1(a<<1|1,mid+1,r);
            dat_j[a]=dat_j[a<<1]^dat_j[a<<1|1];
        }
    }
    void build2(int a,int l,int r){
        if(l==r)    dat_o[a]=num2[l];
        else{
            int mid=(l+r)>>1;
            build2(a<<1,l,mid);
            build2(a<<1|1,mid+1,r);
            dat_o[a]=dat_o[a<<1]^dat_o[a<<1|1];
        }
    }
    void update1(int a,int l,int r,int m,int x){
        if(l==r)    dat_j[a]=x;
        else{
            int mid=(l+r)>>1;
            if(m<=mid)    update1(a<<1,l,mid,m,x);
            else    update1(a<<1|1,mid+1,r,m,x);
            dat_j[a]=dat_j[a<<1]^dat_j[a<<1|1];
        }
    }
    void update2(int a,int l,int r,int m,int x){
        if(l==r)    dat_o[a]=x;
        else{
            int mid=(l+r)>>1;
            if(m<=mid)    update2(a<<1,l,mid,m,x);
            else    update2(a<<1|1,mid+1,r,m,x);
            dat_o[a]=dat_o[a<<1]^dat_o[a<<1|1];
        }
    }
    int query1(int a,int l,int r,int x,int y){
        if(x>r || y<l)    return 0;
        if(x<=l && r<=y    )    return dat_j[a];
        int mid=(l+r)>>1;
        return query1(a<<1,l,mid,x,y)^query1(a<<1|1,mid+1,r,x,y);
    }
    int query2(int a,int l,int r,int x,int y){
        if(x>r || y<l)    return 0;
        if(x<=l && r<=y    )    return dat_o[a];
        int mid=(l+r)>>1;
        return query2(a<<1,l,mid,x,y)^query2(a<<1|1,mid+1,r,x,y);
    }
    int main(){
        int T;
        scanf("%d",&T);
        for(int i=1;i<=T;i++){
            printf("Case #%d:
    ",i);
            int n,m;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)    scanf("%d",&num[i]);
            int p=0;
            for(int i=1;i<=n;i+=2)    num1[++p]=num[i];
            p=0;
            for(int i=2;i<=n;i+=2)    num2[++p]=num[i];
            build1(1,1,(n+1)/2);
            build2(1,1,n/2);
            for(int i=0;i<m;i++){
                int t,l,r;
                scanf("%d%d%d",&t,&l,&r);
                if(t==0){
                    if(l%2==1)    update1(1,1,(n+1)/2,(l+1)/2,r);
                    else    update2(1,1,n/2,l/2,r);
                }
                else{
                    int res=0;
                    int sum=r-l+1;
                    if(sum%2==0)    printf("0
    ");
                    else{
                        if(l%2==1){
                            printf("%d
    ",query1(1,1,(n+1)/2,(l+1)/2,(r+1)/2));
                        }
                        else{
                            printf("%d
    ",query2(1,1,n/2,l/2,r/2));
                        }
                    }
                }
            }
        }
    }
  • 相关阅读:
    并查集_贪心_求无向图最短连通路径_最小生成树(kruskal)
    01背包&&完全背包_顺序枚举和逆序枚举的问题_一维数组
    week7_简单题_C_水题_hdu_5578+F_贪心_hdu_5583
    计量经济学_大纲
    概率专题_概率/ 数学_基础题_ABEI
    动态规划_01背包_从Dijikstra和Floyd入手,彻底理解01背包
    动态规划_基础_最长公共子序列_多种方法_递归/dp
    动态规划_基础_分治思想_从归并排序到任意子区间序列求和_滑动窗口+递推
    分治思想_归并排序_各种写法和思路(待续)
    递归基础_整数划分类问题_ 多状态转移复杂递推
  • 原文地址:https://www.cnblogs.com/qingjiuling/p/11233873.html
Copyright © 2011-2022 走看看