CF 482 B. Interesting Array 线段树

本文介绍了一种使用线段树解决特定区间并运算问题的方法。针对CF482B题目,通过线段树实现了区间更新和查询,确保数组满足给定条件。最后给出了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

敲了很久所以mark一下,辣鸡!

原题见CF 482B

试给出n个数,满足m个条件,每个条件即第l个数到第r个数这连续几个数的&值等于q。n和m范围为 1105 ,q的范围为0到 230 .

分析

同一个数如果要满足多个条件,则这个数值为q的
每次满足的条件要对一个区间的值取(旧值新值),对于区间操作,利用线段树来操作。
所有条件标记完以后,向下更新到所有结点。
再反过来检验是否满足m个条件(之前的操作可能会使一些位没有0),即线段树的查询操作。ATTENTION:先要从叶节点向上更新区间的&和之前没更新竟然过了,数据太弱了。
写完之后感觉也不是很难嘛……辣鸡

附代码

/*--------------------------------------------
 * File Name: CF 482B
 * Author: Danliwoo
 * Mail: Danliwoo@outlook.com
 * Created Time: 2016-07-08 10:15:09
--------------------------------------------*/

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 101000
#define M 32
int n, m, tre[N*3];
struct node
{
    int l, r, v;
    void pr(){
        printf("%d %d %d %d\n", m, l, r, v);
    }
}p[N];
void update(int rt, int l, int r, int bg, int ed, int v){
    if(r < bg || ed < l || bg > ed) return;
    if(bg <= l && r <= ed){
        tre[rt] |= v;
        return;
    }
    int mid = l+r >> 1;
    update(rt<<1, l, mid, bg, ed, v);
    update(rt<<1|1, mid+1, r, bg, ed, v);
}
void down(int rt, int l, int r){
    if(l == r) return;
    tre[rt<<1] |= tre[rt];
    tre[rt<<1|1] |= tre[rt];
    int mid = l+r >> 1;
    down(rt<<1, l, mid);
    down(rt<<1|1, mid+1, r);
}
int test(int rt, int l, int r, int bg, int ed){
    if(r < bg || ed < l || bg > ed) return 0x7fffffff;
    if(bg <= l && r <= ed){
        return tre[rt];
    }
    int res = 0x7fffffff, mid = l+r >> 1;
    res &= test(rt<<1, l, mid, bg, ed);
    res &= test(rt<<1|1, mid+1, r, bg, ed);
    return res;
}
void pr(int rt, int l, int r){
    if(l == r){
        if(l > 1) printf(" ");
        printf("%d", tre[rt]);
        return;
    }
    int mid = r+l >> 1;
    pr(rt<<1, l, mid);
    pr(rt<<1|1, mid+1, r);
}
int change(int rt, int l, int r){
    if(l == r) return tre[rt];
    int mid = l+r >> 1;
    change(rt<<1, l, mid);
    change(rt<<1|1, mid+1, r);
    return tre[rt] = tre[rt<<1] & tre[rt<<1|1];
}
bool solve(){
    down(1, 1, n);
    change(1, 1, n);
    for(int i = 0;i < m;i++)
        if(test(1, 1, n, p[i].l, p[i].r) != p[i].v)
            return false;
    printf("YES\n");
    pr(1, 1, n);
    printf("\n");
    return true;
}
int main()
{
    while(~scanf("%d%d", &n, &m)){
        memset(tre, 0, sizeof(tre));
        for(int i = 0;i < m;i++)
            scanf("%d%d%d", &p[i].l, &p[i].r, &p[i].v);
        memset(tre, 0, sizeof(tre));
        for(int i = 0;i < m;i++)
            update(1, 1, n, p[i].l, p[i].r, p[i].v);
        if(!solve()) printf("NO\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值