2017年第0届浙江工业大学之江学院程序设计竞赛决赛—I(主席树)

Problem I: qwb VS 去污棒

Time Limit: 2 Sec   Memory Limit: 256 MB
Submit: 130   Solved: 48
[ Submit][ Status][ Web Board]

Description

qwb表白学姐失败后,郁郁寡欢,整天坐在太阳底下赏月。在外人看来,他每天自言自语,其实他在和自己的影子“去污棒”聊天。
去污棒和qwb互相出题考验对方,去污棒问了qwb这样一个问题:
现已知一个有n个正整数的序列a[1],a[2]...a[n],接下来有m个操作

操作一共有两种:

1.在序列末尾添加一个数x。

2.查询suf[p] xor x的最大值,其中xor是异或 ,l<=p<=r,
suf[t]表示从t开始的后缀的异或和,即 suf[t]=a[t] xor a[t+1] xor ...xor a[len],len为序列长度。

Input

第一行一个整数T(<=5),表示一共有T组数据。

每组数据第一行两个整数n(<=200000),m(<=200000),意义如上所述。

随后一行有n个数,表示初始序列。
随后m行,每行表示一个操作。
操作有两种,1: x 表示在末尾添加一个x,2: l r x表示查询suf[p] xor x的最大值,其中l<= p <= r,
所有数及x不超过224 且保证 所有操作合法。

Output

每组测试数据的第一行输出"Case x:",x为数据组数的标号,从1开始。

接下来,对每个操作2输出一行答案。

Sample Input

1
5 5
1 2 3 4 5
2 1 3 4
1 10
1 7
2 4 4 5
2 1 5 19

Sample Output

Case 1:
6
9
31
想法:
主席树模板
注意一下求前缀和的时候,要加入一个0表示最开始的前缀和。
代码:
#include<cstdio>    
#include<cstring>    
#include<cstdlib>    
#include<cmath>    
#include<algorithm>    
#include<iostream>    
#define maxn 600010    
#define N maxn*27    
     
using namespace std;    
     
int lch[N],rch[N],size[N],root[maxn];    
int n,m,tot,T,sum;    
char s[5];    
     
int modify(int pre,int i,int x)    
{    
    int now=++tot;    
    if (i==0)    
    {    
        lch[now]=rch[now]=0;size[now]=size[pre]+1;    
    }    
    else   
    {    
        int mid=((x>>(i-1))&1);    
        if (mid==0)    
        {    
            rch[now]=rch[pre];lch[now]=modify(lch[pre],i-1,x);    
        }    
        else   
        {    
            lch[now]=lch[pre];rch[now]=modify(rch[pre],i-1,x);    
        }    
        size[now]=size[lch[now]]+size[rch[now]];    
    }    
    return now;    
}    
     
int query(int root1,int root2,int i,int x)    
{    
    if (i==0) return 0;    
    int mid=((x>>(i-1))&1);    
    if (mid==0)    
    {    
        if (size[rch[root2]]-size[rch[root1]]) return (1<<(i-1))+query(rch[root1],rch[root2],i-1,x);    
        else return query(lch[root1],lch[root2],i-1,x);    
    }    
    else   
    {    
        if (size[lch[root2]]-size[lch[root1]]) return (1<<(i-1))+query(lch[root1],lch[root2],i-1,x);    
        else return query(rch[root1],rch[root2],i-1,x);    
    }    
}    
     
int main()    
{    
    int pp;scanf("%d",&pp);  
    for (int p=1;p<=pp;p++)  
    {  
        printf("Case %d:\n",p);  
        scanf("%d%d",&n,&T);    
        root[0]=lch[0]=rch[0]=size[0]=0;    
        root[0]=modify(root[0],25,0);    
        for (int i=1;i<=n;i++)    
        {    
            int x;    
            scanf("%d",&x);sum^=x;    
            root[i]=modify(root[i-1],25,sum);    
        }    
        while (T--)    
        {    
            int l,r,x;    
            scanf("%s",s+1);    
            if (s[1]=='1')    
            {    
                scanf("%d",&x);    
                sum^=x;    
                n++;root[n]=modify(root[n-1],25,sum);    
            }    
            else   
            {    
                scanf("%d%d%d",&l,&r,&x);    
                l--;r--;    
                printf("%d\n",query(root[l-1],root[r],25,sum^x));    
            }    
        }  
    }  
    return 0;    
}    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值