洛谷:P哥的桶(线段树 + 线性基)

题目背景

P哥在IOI取得了金牌,现在他开始找女朋友了!

题目描述

P哥现在有nn个桶,他们排成了一排,这些桶可以装下任意多个女朋友。每个女朋友有一个固定的颜值

P哥时不时地会找新女朋友,并把新找的女朋友丢进某个桶里面。我们用1\;k\;x1kx来表示P哥找了一个颜值为xx的女朋友,并且丢进了kk号桶里面

P哥每天晚上需要在特定的桶里面找一些女朋友观赏。我们用2\;l\;r2lr来表示P哥在ll号桶到rr号桶之间找女朋友。P哥希望观赏的女朋友颜值异或和尽可能大。

注意:P哥观赏完这些后会女朋友把它们物归原位

输入输出格式

输入格式:

 

第一行两个整数n,mn,m,依次表示P哥的操作次数、这组数据会涉及到的最大编号

接下来nn行,每行三个整数,表示操作。操作格式如题

 

输出格式:

 

对于每个观赏操作,输出P哥能观赏到的最大颜值异或和

 

输入输出样例

输入样例#1: 复制

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

输出样例#1: 复制

3
7

输入样例#2: 复制

11 10
2 6 9
1 9 1523456696
1 1 1818963290
2 6 7
1 1 102229226
2 1 9
2 3 7
1 5 34895532
1 1 1652480680
1 1 1477666032
2 1 10

输出样例#2: 复制

0
0
1818963290
0
1857442578

说明

对于20%的数据,满足n,m\leq 100n,m≤100

对于40%的数据,满足n,m\leq 1000n,m≤1000

另有20%的数据,所有询问满足l=1,r=ml=1,r=m

对于100%的数据,满足n,m\leq 5*10^4\;\;\;l\leq r\leq m\;\;\;k\leq m\;\;\;x\leq 2^{31}-1n,m≤5∗104l≤r≤mk≤mx≤231−1

题意:N个操作,第K个桶放一个X,查询L到R区间的桶任意数的异或最大值。

思路:线段树,每个节点维护区间的线性基,因为数据比较随机,所以判断线性基满了直接返回就能优化复杂度。

线性基:将一堆数(设最大值为MAX)压成log2(MAX)个数,可以求出它们异或的最大值,或者能否异或出某个数。

# include <bits/stdc++.h>
# define lson l,mid,id<<1
# define rson mid+1,r,id<<1|1
using namespace std;
typedef long long LL;
const int maxn = 5e4+30;
struct node{
    int bit[32], len;
}a[maxn<<2];
void fun(node &x, int val){
    if(x.len == 31) return;
    for(int i=30; ~i; --i){
        if(val&(1<<i)){
            if(x.bit[i] == 0){
                x.bit[i] = val;
                ++x.len;
                break;
            }
            else val ^= x.bit[i];
        }
    }
}
void update(int pos, int val, int l, int r, int id){
    fun(a[id], val);
    if(l == r) return;
    int mid = l+r>>1;
    if(pos <= mid) update(pos, val, lson);
    else update(pos, val, rson);
}
node Merge(node x, node y){
    if(x.len == 31) return x;
    if(y.len == 31) return y;
    node tmp = x;
    for(int i=30; ~i; --i)
        if(y.bit[i])
            fun(tmp, y.bit[i]);
    return tmp;
}
node query(int L, int R, int l, int r, int id){
    if(L<=l && R>=r) return a[id];
    int mid = l+r>>1;
    if(R <= mid) return query(L, R, lson);
    else if(L > mid) return query(L, R, rson);
    else return Merge(query(L, R, lson), query(L, R, rson));
}
int main(){
    int n, m, op, x, y;
    scanf("%d%d",&n,&m);
    while(n--){
        scanf("%d%d%d",&op,&x,&y);
        if(op == 1) update(x, y, 1, m, 1);
        else{
            node tmp = query(x, y, 1, m, 1);
            int ans = 0;
            for(int i=30; ~i; --i)
                if((ans^tmp.bit[i]) > ans) ans ^= tmp.bit[i];
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值