FZU2105 Digits Count(按位建线段树)题解

题意:

给出区间与、或、异或\(x\)操作,还有询问区间和。

思路:

因为数比较小,我们给每一位建线段树,这样每次只要更新对应位的答案。
与\(0\)和或\(1\)相当于重置区间,异或\(1\)相当于翻转区间,那么设出两个\(lazy\)搞一下。注意父区间\(pushdown\)重置标记时,子区间的翻转标记要清空。

代码:

#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <stack>
#include <ctime>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const int maxn = 1e6 + 5;
const int MAXM = 3e6;
const ll MOD = 1e9 + 7;
const ull seed = 131;
const int INF = 0x3f3f3f3f;

#define lson (rt << 1)
#define rson (rt << 1 | 1)
int sum[5][maxn << 2];
int lazy[5][maxn << 2], rev[5][maxn << 2];
int a[maxn];
void pushup(int rt, int bit){
    sum[bit][rt] = sum[bit][lson] + sum[bit][rson];
}
void pushdown(int rt, int bit, int l, int r){
    int m = (l + r) >> 1;
    if(lazy[bit][rt] != -1){
        sum[bit][lson] = lazy[bit][rt] * (m - l + 1);
        sum[bit][rson] = lazy[bit][rt] * (r - m);
        lazy[bit][lson] = lazy[bit][rson] = lazy[bit][rt];
        rev[bit][lson] = rev[bit][rson] = 0;    //!!!!!
        lazy[bit][rt] = -1;
    }
    if(rev[bit][rt]){
        sum[bit][lson] = m - l + 1 - sum[bit][lson];
        sum[bit][rson] = r - m - sum[bit][rson];
        rev[bit][lson] ^= 1;
        rev[bit][rson] ^= 1;
        rev[bit][rt] = 0;
    }
}
void build(int l, int r, int bit, int rt){
    lazy[bit][rt] = -1;
    rev[bit][rt] = 0;
    if(l == r){
        sum[bit][rt] = (a[l] >> bit) & 1;
        return;
    }
    int m = (l + r) >> 1;
    build(l, m, bit, lson);
    build(m + 1, r, bit, rson);
    pushup(rt, bit);
}
void update(int L, int R, int l, int r, int op, int bit, int rt){
    if(L <= l && R >= r){
        if(op == 1){    //&0
            lazy[bit][rt] = 0;
            rev[bit][rt] = 0;
            sum[bit][rt] = 0;
        }
        else if(op == 2){   //|1
            lazy[bit][rt] = 1;
            rev[bit][rt] = 0;
            sum[bit][rt] = r - l + 1;
        }
        else{   //^1
            rev[bit][rt] ^= 1;
            sum[bit][rt] = r - l + 1 - sum[bit][rt];
        }
        return;
    }
    pushdown(rt, bit, l, r);
    int m = (l + r) >> 1;
    if(L <= m)
        update(L, R, l, m, op, bit, lson);
    if(R > m)
        update(L, R, m + 1, r, op, bit, rson);
    pushup(rt, bit);
}
int query(int L, int R, int l, int r, int bit, int rt){
    if(L <= l && R >= r){
        return sum[bit][rt];
    }
    pushdown(rt, bit, l, r);
    int m = (l + r) >> 1, ret = 0;
    if(L <= m)
        ret += query(L, R, l, m, bit, lson);
    if(R > m)
        ret += query(L, R, m + 1, r, bit, rson);
    return ret;
}
int main(){
    int n, m, T;
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for(int i = 0; i < 5; i++) build(1, n, i, 1);
        while(m--){
            int op, l, r, x;
            char ope[10];
            scanf("%s", &ope);
            if(ope[0] == 'A') op = 1;
            else if(ope[0] == 'O') op = 2;
            else if(ope[0] == 'X') op = 3;
            else op = 4;
            if(op == 4){
                scanf("%d%d", &l, &r);
                l++, r++;
                ll ans = 0;
                for(int i = 0; i < 5; i++){
                    x = query(l, r, 1, n, i, 1);
                    ans += 1LL * (1LL << i) * x;
                }
                printf("%lld\n", ans);
            }
            else{
                scanf("%d%d%d", &x, &l, &r);
                l++, r++;
                if(op == 2 || op == 3){
                    for(int i = 0; i < 5; i++){
                        if((x >> i) & 1)
                            update(l, r, 1, n, op, i, 1);
                    }
                }
                else{
                    for(int i = 0; i < 5; i++){
                        if(!((x >> i) & 1))
                            update(l, r, 1, n, op, i, 1);
                    }
                }
            }
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/KirinSB/p/11489274.html

时间: 2024-10-11 00:40:53

FZU2105 Digits Count(按位建线段树)题解的相关文章

POJ 2777 Count Color(位运算+线段树+lazy+区间更新)

Count Color Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 39905   Accepted: 12034 Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem.

ZOJ 1610 Count the Colors (线段树区间更新)

题目链接 题意 : 一根木棍,长8000,然后分别在不同的区间涂上不同的颜色,问你最后能够看到多少颜色,然后每个颜色有多少段,颜色大小从头到尾输出. 思路 :线段树区间更新一下,然后标记一下,最后从头输出. //ZOJ 1610 #include <cstdio> #include <cstring> #include <iostream> using namespace std ; int p[8010*4],lz[8010*4] ,hashh[8010*4],has

ZOJ1610 Count the Colors 经典线段树染色问题

题意,给你n个  x,y,c,意思就是区间[x,y]被染成C色,但是颜色会被覆盖的,染色操作完成以后 问你每种颜色有多少段 并输出颜色编号id跟段数cnt 经典问题,不过写的有点撮吧,没去看别人的,这个方法应该是最传统的最普通的,常规的开数组记录,也许大神们有更高端的方法 #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring>

非结构体线段树版 ZJU 1610 Count the Colors (线段树区间更新)

Painting some colored segments on a line, some previously painted segments may be covered by some the subsequent ones. Your task is counting the segments of different colors you can see at last. Input The first line of each data set contains exactly

FZU-2105 Digits Count (两种标记成段更新)

题目大意:给n个0~15之间的数,有3种更新操作,1种询问操作.3种更新操作是:1.让某个闭区间的所有数字与一个0~15之间的数字进行逻辑与运算:2.让某个闭区间的所有数字与一个0~15之间的数字进行逻辑或运算:3.让某个闭区间的所有数字与一个0~15之间的数字进行异或运算.一种询问操作是询问某个闭区间的所有数字之和. 题目分析:所有的输入数字都是在0~15之间,可以二进制中的每一位建立线段树,建立四棵.3种更新操作实际上只有两种,即区间置位和区间反转.用两个懒惰标记,当进行区间置位更新的时候,

线段树&#183;题解报告

线段树·题解报告 参考资料 ·课件 线段树 --刘汝佳 统计的力量,线段树全接触 --张昆玮 ·Blog [完全版]线段树 从普通线段树到zkw线段树 [总结][数据结构]ZKW线段树详解 选题目录 · Hdu1166 敌兵布阵(单点更新,区间求和) · Hdu1754 I Hate It(单点更新,RMQ) · Hdu3308 LCIS(单点更新,区间并) · Poj3468 A Simple Problem with Integers(区间加减,区间求和) · Poj2777 Count C

POJ 2528 Mayor&#39;s posters 离散化和线段树题解

本题就是要往墙上贴海报,问最后有多少可见的海报. 其实本题的难点并不是线段树,而是离散化. 因为数据很大,直接按原始数据计算那么就会爆内存和时间的. 故此需要把数据离散化. 比如有海报1 6   7 9   20 100  5 1000的原始数据,直接计算需要1-1000的内存,离散化之后只需要8内存,因为只有4组数据8个数. 本题更进一步高级一点的离散化就是需要把不相邻的两个数据插入一个数值,表示有空白的地方,不是所有海报都覆盖到的. 比如上面的数据要离散为:1 2  5 6  7 8 9 1

POJ 2528 Mayor&amp;#39;s posters 离散化和线段树题解

本题就是要往墙上贴海报,问最后有多少可见的海报. 事实上本题的难点并非线段树,而是离散化. 由于数据非常大,直接按原始数据计算那么就会爆内存和时间的. 故此须要把数据离散化. 比方有海报1 6   7 9   20 100  5 1000的原始数据.直接计算须要1-1000的内存,离散化之后仅仅须要8内存,由于仅仅有4组数据8个数. 本题更进一步高级一点的离散化就是须要把不相邻的两个数据插入一个数值.表示有空白的地方,不是全部海报都覆盖到的. 比方上面的数据要离散为:1 2  5 6  7 8

BZOJ 3211 花神游历各国 线段树题解

BZOJ 3211 花神游历各国 线段树题解 3211: 花神游历各国 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 2551  Solved: 946[Submit][Status][Discuss] Description Input Output 每次x=1时,每行一个整数,表示这次旅行的开心度 Sample Input 4 1 100 5 5 5 1 1 2 2 1 2 1 1 2 2 2 3 1 1 4 Sample Output 101