0
点赞
收藏
分享

微信扫一扫

2021“MINIEYE杯”中国大学生算法设计超级联赛(8) - 1004(Counting Stars)

补题链接: ​​https://acm.hdu.edu.cn/showproblem.php?pid=7059​​

考点: ​​线段树​

解题思路可参考​

但是与下面的代码不同的是: 下面代码考虑的是​​flag = true​​ 代表[l, r]区间内ai为0,即高位和低位都为0;

​AC Code​

#include <iostream>

using namespace std;

typedef long long ll;

const int mod = 998244353, N = 1e5 + 10;

int n, q;

// x 位代表a的二进制表示中最左边的1的位置
// lo: 记录a的前x-1位的大小
// hi: 记录a的x位的10进制表示的大小
ll lo[N], hi[N];

struct SegmentTree{

int l, r; // 区间
ll sum1, sum2; // lo的区间和; hi的区间和
bool flag; // [l, r]区间每个ai都是0
ll tag2; // ai + 2^k(相当于最高位*2)的懒标记; tag2的值代表[l, r]区间的每个hi需要乘多少

}tree[N << 2];

ll lowbit(ll x){
return x & (-x);
}

void build(int node, int l, int r){

// 初始化
tree[node].l = l, tree[node].r = r;
tree[node].flag = 0;
tree[node].tag2 = 1;
if(l == r){

tree[node].sum1 = lo[l];
tree[node].sum2 = hi[l];
// 如果[l, r]的ai除最高位外,其余位都为0(sum1=0),flag=true;
if(!tree[node].sum2) tree[node].flag = 1;
return;
}

int mid = (l + r) >> 1;

int left_node = node << 1;
int right_node = node << 1 | 1;

build(left_node, l, mid);
build(right_node, mid + 1, r);

tree[node].sum1 = (tree[left_node].sum1 + tree[right_node].sum1) % mod;
tree[node].sum2 = (tree[left_node].sum2 + tree[right_node].sum2) % mod;

// 只有两边都为0; 父节点才为0
tree[node].flag = tree[left_node].flag & tree[right_node].flag;
}

// 关于pushDown操作: 当某操作向当前节点的子节点走时,一定要先执行pushDown操作
void pushDown(int node){

int left_node = node << 1;
int right_node = node << 1 | 1;

tree[left_node].tag2 = tree[left_node].tag2 * tree[node].tag2 % mod;
tree[right_node].tag2 = tree[right_node].tag2 * tree[node].tag2 % mod;

tree[left_node].sum2 = tree[left_node].sum2 * tree[node].tag2 % mod;
tree[right_node].sum2 = tree[right_node].sum2 * tree[node].tag2 % mod;

tree[node].tag2 = 1;
}

// 暴力lowbit操作
void modify1(int node, int L, int R){

if(tree[node].l == tree[node].r){

// 如果当前ai的除了最高位都为0
if(!tree[node].sum1){
// 将 最高位 置0
tree[node].sum2 = 0;
tree[node].flag = 1;
tree[node].tag2 = 1;
return;
}
tree[node].sum1 -= lowbit(tree[node].sum1);

return;
}

// 如果当前区间内所有位都是0
// 所以tag2要变为1

if(L <= tree[node].l && tree[node].r <= R && tree[node].flag){

// tree[node].sum1 = tree[node].sum2 = 0;
tree[node].tag2 = 1;
return;
}

pushDown(node);

int mid = (tree[node].l + tree[node].r) >> 1;
int left_node = node << 1;
int right_node = node << 1 | 1;

if(L <= mid) modify1(left_node, L, R);
if(R > mid) modify1(right_node, L, R);

tree[node].sum1 = (tree[left_node].sum1 + tree[right_node].sum1) % mod;
tree[node].sum2 = (tree[left_node].sum2 + tree[right_node].sum2) % mod;

tree[node].flag = tree[left_node].flag & tree[right_node].flag;
}

// + 2^k操作, 相当于高位*2
void modify2(int node, int L, int R){

if(L <= tree[node].l && tree[node].r <= R){

tree[node].sum2 = tree[node].sum2 * 2 % mod;
tree[node].tag2 = tree[node].tag2 * 2 % mod;
return;
}

pushDown(node);

int mid = (tree[node].l + tree[node].r) >> 1;
int left_node = node << 1;
int right_node = node << 1 | 1;

if(L <= mid) modify2(left_node, L, R);
if(R > mid) modify2(right_node, L, R);

tree[node].sum1 = (tree[left_node].sum1 + tree[right_node].sum1) % mod;
tree[node].sum2 = (tree[left_node].sum2 + tree[right_node].sum2) % mod;

tree[node].flag = tree[left_node].flag & tree[right_node].flag;
}

// query
ll ask(int node, int L, int R){

if(L <= tree[node].l && tree[node].r <= R){
return (tree[node].sum1 + tree[node].sum2) % mod;
}

pushDown(node);

ll res = 0;
int mid = (tree[node].l + tree[node].r) >> 1;
int left_node = node << 1;
int right_node = node << 1 | 1;

if(L <= mid) res += ask(left_node, L, R);
if(R > mid) res = (res + ask(right_node, L, R)) % mod;

return res;
}


int main(){

int t;
scanf("%d", &t);

while (t--){

scanf("%d", &n);

ll a;
for (int i = 1; i <= n; ++i) {

scanf("%lld", &a);
hi[i] = lo[i] = 0; // 清空
for (int j = 30; j > 0; j--) {

// 计算a的lo值和hi值
if((1ll << j) <= a){
hi[i] = (1ll << j);
lo[i] = a & (~hi[i]);
break;
}
}
}

// 建树
build(1, 1, n);

scanf("%d", &q);
for (int i = 1; i <= q; ++i) {

int opt, l, r;
scanf("%d%d%d", &opt, &l, &r);
if(opt == 1){
printf("%lld\n", ask(1, l, r));
}else if(opt == 2){
modify1(1, l, r);
}else{
modify2(1, l, r);
}
}
}

return 0;
}


举报

相关推荐

0 条评论