zoukankan      html  css  js  c++  java
  • 2019icpc南昌邀请赛F(线段树)

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

    题意:给长为n的数组a,有m次操作,包括单点修改和查询F(l,r),其值为所有f(i,j)的异或和,l<=i<=j<=r,即

    其中

    (n,m<=1e5).

    思路:这种题可以用线段树来进行修改和查询,但需要先化简。对于l<=x<=r,包括ax的区间有(r-x+1)*(x-l+1)个,注意到当区间长为偶数时,改值恒为偶数,那么也就是说ax出现偶数次,那么查询结果为0。当区间长度为奇数时,若x与l奇偶性不同,则该值为偶数,异或值为0; 若奇偶值相同,则该值为奇数,异或值为ax,故需要用线段树维护与l奇偶性相同的元素的异或和。

       但是合并两个区间的时候,可能出现右区间的l与左区间的l奇偶性不同的情况,这时,右区间维护的值不能直接求与。需要同右区间整体异或和异或之后得到与左区间的l奇偶性相同的那些元素的异或和。说的很绕,手动算一下就明白,所以我们还需要用线段树维护区间的异或和。

    AC代码:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    const int maxn=100005;
    
    int T,n,m,cas,a[maxn];
    
    struct node{
        int l,r;
        int sum,val;
    }tr[maxn<<2];
    
    void pushup(int v){
        tr[v].sum=tr[v<<1].sum^tr[v<<1|1].sum;
        if((tr[v<<1|1].l-tr[v].l)%2==0)
            tr[v].val=tr[v<<1].val^tr[v<<1|1].val;
        else
            tr[v].val=tr[v<<1].val^(tr[v<<1|1].sum^tr[v<<1|1].val);
    }
    
    void build(int v,int l,int r){
        tr[v].l=l,tr[v].r=r;
        if(l==r){
            tr[v].sum=tr[v].val=a[l];
            return;
        }
        int mid=(l+r)>>1;
        build(v<<1,l,mid);
        build(v<<1|1,mid+1,r);
        pushup(v);
    }
    
    void update(int v,int x,int y){
        if(tr[v].l==tr[v].r){
            tr[v].sum=tr[v].val=y;
            return;
        }
        int mid=(tr[v].l+tr[v].r)>>1;
        if(x<=mid) update(v<<1,x,y);
        else update(v<<1|1,x,y);
        pushup(v);
    }
    
    void query(int v,int l,int r,int& x,int& y){
        if(tr[v].l==l&&tr[v].r==r){
            x=tr[v].val;
            y=tr[v].sum;
            return;
        }    
        int mid=(tr[v].l+tr[v].r)>>1;
        if(r<=mid)
            query(v<<1,l,r,x,y);
        else if(l>mid)
            query(v<<1|1,l,r,x,y);
        else{
            int a,b,c,d;
            query(v<<1,l,mid,a,b);
            query(v<<1|1,mid+1,r,c,d);
            if((tr[v<<1|1].l-l)%2==0)
                x=a^c,y=b^d;
            else
                x=a^(d^c),y=b^d;
        }
    }
    
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;++i)
                scanf("%d",&a[i]);
            build(1,1,n);
            printf("Case #%d:
    ",++cas);
            while(m--){
                int op,x,y;
                scanf("%d%d%d",&op,&x,&y);
                if(op==0)
                    update(1,x,y);
                else{
                    if((y-x+1)%2==0)
                        printf("0
    ");
                    else{
                        int a,b;
                        query(1,x,y,a,b);
                        printf("%d
    ",a);
                    }
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    UVA 1599 Ideal Path(双向bfs+字典序+非简单图的最短路+队列判重)
    UVA 1572 Self-Assembly(拓扑排序)
    最大流当前弧优化Dinic分层模板
    POJ 3683.Priest John's Busiest Day 2-SAT
    n的m划分 整数拆分问题
    表达式计算
    大白书中无向图的点双联通分量(BCC)模板的分析与理解
    Codeforces 766D. Mahmoud and a Dictionary 并查集 二元敌对关系 点拆分
    树状数组入门
    Tire树入门专题
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/11238337.html
Copyright © 2011-2022 走看看