题意:给你一个数组a,长度为。有两种操作。一种是改变数组的某个元素的值,一种是满足某种条件的数组b有多少种。条件是:b[i] <= a[i],并且b[1]^b[2]...^b[n] = k的数组有多少种。数组a的元素都小于1000.

思路:因为数很小,我们把数变成二进制数,然后拆分二进制数。比如1101可以拆成10xx,x可为0可为1,有点像数位dp的试填法。我们对每个a[i]存若干个前缀,记录前缀的长度,以及是这个前缀的二进制数有多少个。然后我们合并相邻的区间,直接暴力二重循环,然后合并。其实这个过程更像dp的过程,感觉只是用了线段树的划分成区间,然后合并的思想。

思路参考这两篇博客:https://blog.csdn.net/jtjy568805874/article/details/56488626, https://blog.csdn.net/qian99/article/details/38171951

代码:

#include <bits/stdc++.h>
#define pii pair<int, int>
#define lowbit(x) (x & (-x))
#define mk make_pair
#define ls(x) (x << 1)
#define rs(x) ((x << 1) | 1)
#define LL long long
using namespace std;
const LL mod = 1000000007;
const int maxn = 20010; int Log[2010], a[maxn];
struct node {
pii x;
LL tot;
bool operator < (const node& rhs) const {
return x < rhs.x;
}
}; vector<node> tr[maxn * 4], tmp; int get(int x, int y) {
tr[x].clear();
tr[x].push_back((node){mk(y, 10), 1});
for (int i = y; i; i -= lowbit(i)) {
tr[x].push_back((node){mk(i - lowbit(i), 10 - Log[lowbit(i)]), lowbit(i)});
}
} void pushup(int x, int l, int r) {
tmp.clear();
tr[x].clear();
for (int i = 0; i < tr[l].size(); i++) {
for (int j = 0; j < tr[r].size(); j++) {
node t1 = tr[l][i], t2 = tr[r][j];
int now = t1.x.first ^ t2.x.first, len = min(t1.x.second, t2.x.second);
now = ((now >> (10 - len)) << (10 - len));
tmp.push_back((node){mk(now, len), (t1.tot * t2.tot) % mod});
}
}
sort(tmp.begin(), tmp.end());
for (int i = 0, j; i < tmp.size(); i = j) {
node tmp1 = (node){tmp[i].x, 0};
for (j = i; j < tmp.size() && tmp[i].x == tmp[j].x; j++) {
tmp1.tot = (tmp1.tot + tmp[j].tot) % mod;
}
tr[x].push_back(tmp1);
}
} void build(int x, int l, int r) {
if(l == r) {
get(x, a[l]);
return;
}
int mid = (l + r) >> 1;
build(ls(x), l ,mid);
build(rs(x), mid + 1, r);
pushup(x, ls(x), rs(x));
} LL inv(int x) {
return x == 1 ? 1 : 1ll * inv(mod % x)*(mod - mod / x) % mod;
} void update(int x, int l, int r, int pos, int val) {
if(l == r) {
get(x, val);
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) update(ls(x), l, mid, pos, val);
else update(rs(x), mid + 1, r, pos, val);
pushup(x, ls(x), rs(x));
} LL query(int x) {
LL ans = 0;
for (int i = 0; i < tr[1].size(); i++) {
node t = tr[1][i];
if((t.x.first ^ x) >> (10 - t.x.second)) continue;
ans = (ans + (t.tot * inv(1 << (10 - t.x.second))) % mod) % mod;
}
return ans;
}
int main() {
int n, m;
int x, y;
char s[10];
for (int i = 1; i <= 10; i++)
Log[1 << i] = i;
int T;
cin >> T;
while(T--) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
build(1, 1, n);
while(m--) {
scanf("%s",s + 1);
if(s[1] == 'Q') {
scanf("%d", &x);
printf("%lld\n", query(x));
} else {
scanf("%d%d", &x, &y);
update(1, 1, n, x + 1, y);
}
}
}
}

  

线段树教做人系列(2)HDU 4867 XOR的更多相关文章

  1. 线段树教做人系列(3) HDU 4913

    题意及思路看这篇博客就行了,讲得很详细. 下面是我自己的理解: 如果只有2,没有3的话,做法就很简单了,只需要对数组排个序,然后从小到大枚举最大的那个数.那么它对答案的贡献为(假设这个数排序后的位置是 ...

  2. Codeforces 719E (线段树教做人系列) 线段树维护矩阵

    题面简洁明了,一看就懂 做了这个题之后,才知道怎么用线段树维护递推式.递推式的递推过程可以看作两个矩阵相乘,假设矩阵A是初始值矩阵,矩阵B是变换矩阵,求第n项相当于把矩阵B乘了n - 1次. 那么我们 ...

  3. 线段树教做人系列(1)HDU4967 Handling the Past

    题意:给你n组操作,分别为压栈,出栈,询问栈顶元素.每一组操作有一个时间戳,每次询问栈顶的元素的操作询问的是在他之前出现的操作,而且时间戳小于它的情况.题目中不会出现栈为空而且出栈的情况. 例如: p ...

  4. Codeforces 1136E Nastya Hasn't Written a Legend (线段树教做人系列)

    题意:有一个数组a和一个数组k,数组a一直保持一个性质:a[i + 1] >= a[i] + k[i].有两种操作:1,给某个元素加上x,但是加上之后要保持数组a的性质.比如a[i]加上x之后, ...

  5. 线段树(单点更新,区间查询) HDU 1754 I Hate It

    题目链接 线段树的模板 #include<iostream> #include<cstdio> #include<cmath> #include<algori ...

  6. 线段树(区间合并)HDU - 1540

    题意:输入n,m,给定n个相互连通的村庄,有m个操作,D x,表示破坏x村庄使其与相邻的两个村庄不相通,R 表示修复上一个被破坏的村庄,与相邻的两个村庄联通.Q x表示与x相连的村庄有多少个. 思路: ...

  7. (线段树 区间查询)The Water Problem -- hdu -- 5443 (2015 ACM/ICPC Asia Regional Changchun Online)

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=5443 The Water Problem Time Limit: 1500/1000 MS (Java/ ...

  8. (线段树)Just a Hook -- hdu -- 1689

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=1698 思路: 我的想法很简单,像上一题一样从后面向前面来算,前面已经覆盖的,后面自然不能再来计算了,具体 ...

  9. 线段树(区间修改、区间查询) HDU 1754 I Hate It

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

随机推荐

  1. Tomcat_总结_01_tomcat环境搭建

    一.准备条件 1.安装jdk 二.安装tomcat 1.下载tomcat 去官网下载  64-bit Windows zip  版本的tomcat,并解压 https://tomcat.apache. ...

  2. idea使用git上传项目到coding

    1.VCS -> import into version control -> create git repository 2.选择要上传的项目根目录 3.选择后,项目里的文件名字变成了绿 ...

  3. ps-基础知识

    一.常用名词及几个常见控制面板. 二.工具栏中各工具的名称及使用方法. 三.新建文件的流程和注意事项. 四.光与色的基础知识

  4. Linux U盘 启动盘

    /****************************************************************************** * Linux U盘 启动盘 * 说明: ...

  5. CAP理论、BASE理论

    从分布式一致性谈到CAP理论.BASE理论 https://www.cnblogs.com/szlbm/p/5588543.html 问题的提出 在计算机科学领域,分布式一致性是一个相当重要且被广泛探 ...

  6. Python3.7安装pyspider

    下面是Python3.7安装pyspider的方式,能安装成功但是后期有很多问题,所以不建议,请使用3.5版本的Python进行安装!!!由于要做爬虫工作,所以学习pyspider框架,下面介绍安装步 ...

  7. gulp之sass 监听文件,自动编译

    gulpfile.js文件如下: var gulp = require('gulp'); var sass = require('gulp-sass'); gulp.task('default', f ...

  8. 解决docker 下来镜像出现 error pulling image configuration: Get https://dseasb33srnrn.cloudfront.net的问题

    http://f2d6cb40.m.daocloud.io [root@node2 ~]# docker --version                                       ...

  9. nginx错误

    在开发的时候遇到nginx错误 网上找了半天也没有找到解决方案: 先查看了一下nginx错误日志 cat /usr/local/nginx/logs/error.log 然后发现看不太懂 那么只能重启 ...

  10. error: cast from ‘char*’ to ‘int’ loses precision

    程序: char* addrCom; addrCom= ......//赋值 == (int)addrCom) //导致编译出错 { ...... } 编译时出现错误: error: cast fro ...