题意:给你一个数组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. 清北学堂(2019 5 1) part 4

    今天讲数论 1.进制问题(将n转换成k进制数): 1.方法:短除法 将n/k,保存,将商当做新的n,将余数保存,直到商为0,将余数(包括0),倒序输出,即得n的k进制数 2.关于高精四则运算(我本以为 ...

  2. 51nod 1257 01分数规划/二分

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1257 1257 背包问题 V3 基准时间限制:3 秒 空间限制:1310 ...

  3. MySQL 索引知识整理(创建高性能的索引)

    前言: 索引优化应该是对查询性能优化的最有效的手段了.索引能够轻易将查询性能提高几个数量级. // 固态硬盘驱动器有和机械硬盘启动器,有着完全不同的性能特性: 然而即使是固态硬盘,索引的原则依然成立, ...

  4. GEF入门实例_总结_05_显示一个空白编辑器

    一.前言 本文承接上一节:GEF入门实例_总结_04_Eclipse插件启动流程分析 在第三节( GEF入门实例_总结_03_显示菜单和工具栏  ),我们创建了菜单和工具栏. 这一节,我们来实现:点击 ...

  5. 完成一个servlet 就要在web.xml里面配一个映射,这样就有一个路径供我们 使用????? servlet从页面接收值?

    最后,最容易忘记的是:在dao层中 调用xml里的删除sql语句 后面需要人为加上事务提交.一定要! sqlSession.commit();//jdbc是自动提交,但是mybatis中不是自动提交的 ...

  6. itunesconnect如何提交被决绝过了的相同版本号

    遇到一次审核被拒,打算再次提交时,不想改变版本号,可以在xcode里把build版本号后面几个.1,比如version上次被拒时是1.1.3,build也是1.1.3,这次送审时version不变,b ...

  7. [BZOJ5248][多省联测2018]双木棋chess

    bzoj luogu sol 首先,要保证一个格子的左边和上方都放满了棋子,就需要这个点的左上方那个矩形都放满了棋子. 这样放棋子状态就会是一个自左下至右上的轮廓线. 状态数?\(C_{20}^{10 ...

  8. 双向链表(Double-Linked List)

    public class doubleLinkedList <Item>{ private Node first; private Node last; private int itemc ...

  9. Maven:Resource Path Location Type Project configuration is not up-to-date with pom.xml. Run project configuration update

    Maven构建项目的时候提示: Description Resource Path Location Type Project configuration is not up-to-date with ...

  10. 虚拟环境中的django及相关包安装

    1.先进入虚拟环境 pyenv activate virtualenvname. 2.安装django软件包 安装命令: pip install django==1.7 查看安装结果: python ...