【BZOJ3821/UOJ46】玄学(二进制分组,线段树)
【BZOJ3821/UOJ46】玄学(二进制分组,线段树)
题面
题解
呜,很好的题目啊QwQ。
离线做法大概可以线段树分治,或者直接点记录左右两次操作时的结果,两个除一下就可以直接计算。
强制在线的话,一般而言,分治在线就弄成二进制分组。把所有修改操作进行二进制分组,每次新加入一个修改操作的时候考虑和前面其他的操作合并,提前构出来线段树,按照次序插入。如果一个节点的左右儿子都填满了修改操作的话,那么把它的两个儿子的值进行合并。然而我们发现并不可能每个节点维护一棵线段树来表示所有的位置的值,实际上,因为每次修改影响的都是一段区间,所以可以用\(vector\)记录修改区间,每次只需要把左右儿子的所有断点合并起来分段就好了,这样子每个修改操作每次贡献\(1\)个断点,所以在整个线段树上最多贡献\(log\)个断点,直接暴力合并就可以了。
这样子每次查询就可以直接在线段树上查询啦。
似乎说的不清楚,看看代码就懂了
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 100100
#define lson (now<<1)
#define rson (now<<1|1)
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int type,n,Q,tot,m,lans,a[MAX];
struct Node{int l,r,a,b;}t[MAX<<2];
void calc(int &a,int &b,int x,int y){a=1ll*a*x%m;b=(1ll*b*x+y)%m;}
Node operator+(Node a,Node b){calc(a.a,a.b,b.a,b.b);return a;}
vector<Node> s[MAX<<2];
void Build(int now,int l,int r)
{
s[now].push_back((Node){1,n,1,0});
if(l==r)return;int mid=(l+r)>>1;
Build(lson,l,mid);Build(rson,mid+1,r);
}
void pushup(int now)
{
s[now].clear();
int l1=s[lson].size(),l2=s[rson].size();
for(int i=0,j=0,l=0;i<l1&&j<l2;)
{
int a=s[lson][i].a,b=s[lson][i].b;
calc(a,b,s[rson][j].a,s[rson][j].b);
if(s[lson][i].r<=s[rson][j].r)
{
s[now].push_back((Node){l+1,s[lson][i].r,a,b});
l=s[lson][i].r;
if(s[lson][i].r==s[rson][j].r)++i,++j;
else ++i;
}
else
{
s[now].push_back((Node){l+1,s[rson][j].r,a,b});
l=s[rson][j].r;++j;
}
}
return;
}
bool Modify(int now,int l,int r,int p,Node a)
{
if(l==r)
{
if(a.l!=1)s[now].push_back((Node){1,a.l-1,1,0});
s[now].push_back(a);
if(a.r!=n)s[now].push_back((Node){a.r+1,n,1,0});
return true;
}
int mid=(l+r)>>1;
if(p<=mid){Modify(lson,l,mid,p,a);return false;}
else
{
bool fl=Modify(rson,mid+1,r,p,a);
if(fl)pushup(now);
return true;
}
}
Node Query(int now,int l,int r,int L,int R,int k)
{
if(L==l&&r==R)
{
int l=0,r=s[now].size();
while(l<=r)
{
int mid=(l+r)>>1;
if(s[now][mid].l<=k&&k<=s[now][mid].r)return s[now][mid];
if(s[now][mid].r<k)l=mid+1;
else r=mid-1;
}
}
int mid=(l+r)>>1;
if(R<=mid)return Query(lson,l,mid,L,R,k);
if(L>mid)return Query(rson,mid+1,r,L,R,k);
return Query(lson,l,mid,L,mid,k)+Query(rson,mid+1,r,mid+1,R,k);
}
int main()
{
type=read();
n=read();m=read();
for(int i=1;i<=n;++i)a[i]=read();
Q=read();
while(Q--)
{
int opt=read(),l=read(),r=read();
if(type&1)l^=lans,r^=lans;
if(opt==1)
{
int a=read(),b=read();++tot;
Modify(1,1,100000,tot,(Node){l,r,a,b});
}
else
{
int x=read();if(type&1)x^=lans;
Node u=Query(1,1,100000,l,r,x);
lans=(1ll*u.a*a[x]+u.b)%m;
printf("%d\n",lans);
}
}
return 0;
}
【BZOJ3821/UOJ46】玄学(二进制分组,线段树)的更多相关文章
- [BZOJ 2989]数列(二进制分组+主席树)
[BZOJ 2989]数列(二进制分组+主席树) 题面 给定一个长度为n的正整数数列a[i]. 定义2个位置的graze值为两者位置差与数值差的和,即graze(x,y)=|x-y|+|a[x]-a[ ...
- 【BZOJ5294】[BJOI2018]二进制(线段树)
[BZOJ5294][BJOI2018]二进制(线段树) 题面 BZOJ 洛谷 题解 二进制串在模\(3\)意义下,每一位代表的余数显然是\(121212\)这样子交替出现的. 其实换种方法看,就是\ ...
- bzoj2989&&4170数列——二进制分组+主席树
题意的转化挺巧妙的 可以联想到曼哈顿距离! 并且,所谓的修改还要查询历史版本,并且修改之间不动只算一次,不就是给平面上加一个点吗? 看成(x,a[x])的点 就是一个菱形区域 转切比雪夫距离,变成矩形 ...
- UOJ46 【清华集训2014】玄学 【时间线段树】
题目链接:UOJ 这题的时间线段树非常的妙. 对时间建立线段树,修改的时候在后面加,每当填满一个节点之后就合并进它的父亲. 对于一个节点维护序列,发现这是一个分段函数,合并就是归并排序.于是就形成了差 ...
- 2019.02.12 bzoj5294: [Bjoi2018]二进制(线段树)
传送门 题意简述: 给出一个长度为nnn的二进制串. 你需要支持如下操作: 修改每个位置:1变0,0变1 询问对于一个区间的子二进制串有多少满足重排之后转回十进制值为333的倍数(允许前导000). ...
- 2019.01.21 bzoj2989: 数列(二进制分组+主席树)
传送门 二进制分组入门题. 主席树写错调题2h+2h+2h+体验极差. 题意简述:给一堆点,支持加入一个点,询问有多少个点跟(x,y)(x,y)(x,y)曼哈顿距离不超过kkk. 思路:题目要求的是对 ...
- Multidimensional Queries(二进制枚举+线段树+Educational Codeforces Round 56 (Rated for Div. 2))
题目链接: https://codeforces.com/contest/1093/problem/G 题目: 题意: 在k维空间中有n个点,每次给你两种操作,一种是将某一个点的坐标改为另一个坐标,一 ...
- 洛谷P4428二进制 [BJOI2018] 线段树
正解:线段树 解题报告: 传送门! 话说开始看到这题的时候我想得hin简单 因为关于%3有个性质就是说一个数的各个位数之和%3=这个数%3嘛,小学基础知识? 我就想着,就直接建一棵树,只是这棵树要用个 ...
- BZOJ5294 [BJOI2018] 二进制 【线段树】
BJOI的题目感觉有点难写 题目分析: 首先推一波结论.接下来的一切都在模3意义下 现在我们将二进制位重组,不难发现的是2^0≡1,2^1≡2,2^2≡1,2^3≡2....所以我们考虑这样的式子 2 ...
- BZOJ5294 BJOI2018二进制(线段树)
二进制数能被3整除相当于奇数.偶数位上1的个数模3同余.那么如果有偶数个1,一定存在重排方案使其合法:否则则要求至少有两个0且至少有3个1,这样可以给奇数位单独安排3个1. 考虑线段树维护区间内的一堆 ...
随机推荐
- tensorflow笔记:多层LSTM代码分析
tensorflow笔记:多层LSTM代码分析 标签(空格分隔): tensorflow笔记 tensorflow笔记系列: (一) tensorflow笔记:流程,概念和简单代码注释 (二) ten ...
- HNOI2019 爆零记
HNOI2019爆零记 day \(-inf\) ~ day \(0\) 开学一周之后才停的课,停课之后就开始每天被包菜.我三月份几乎没有更博,就是因为每天都被虐的自闭了. day \(0\) 本来是 ...
- libgdx学习记录26——Polygon多边形碰撞检测
libgdx中Math封装了Polygon这个类,它是由多个定点进行描述实现的,在进行物体间的碰撞时,物体轮廓有时候是不规则的,这时候可以用一个多边形勾勒出其大概的轮廓,对其进行模拟. Polygon ...
- vue 过滤器基本使用
Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化,例如时间戳格式化. 过滤器可以用在: 双花括号插值 v-bind 表达式 (2.1.0+ 开始支持). 过滤器应该被添加在 JavaSc ...
- Python从菜鸟到高手(1):初识Python
1 Python简介 1.1 什么是Python Python是一种面向对象的解释型计算机程序设计语言,由荷兰人吉多·范罗苏姆(Guido van Rossum)于1989年发明,第一个公开发行版 ...
- 利用阿里云的源yum方式安装Mongodb
今天在线上服务器上安装MongoDB,从Mongo官网直接下载链接,结果在下载时发觉速度慢的可怜.迫于无奈,只能找国内的镜像下载.这里选择阿里云的源进行安装,记录如下: 1)在/etc/yum.rep ...
- LVM基础详细说明及动态扩容lvm逻辑卷的操作记录
LVM概念:---------------------------------------------------------------------------------------------- ...
- SQL中not in 和not exists
在SQL中倒是经常会用到子查询,而说到子查询,一般用的是in而不是exists,先不谈效率问题,就先说说会遇到哪些问题. 用到in当取反的时候,肯定先想到的就是not in.但是在使用not in的时 ...
- HAOI2016 找相同字符 后缀自动机
两个串,考虑一建一跑.枚举模式串的位置\(i\),考虑每次统计以\(i\)结尾的所有符合要求的串.在后缀自动机上走时记录当前匹配长度\(curlen\),则当前节点的贡献是\((curlen-len[ ...
- UserControl 的一个值得注意的问题 [属性" * "的代码生成失败.错误是:"程序集"*.Version=1.0.0.0,Culture=neutral,..........无标记为序列化"
开发时在做UserControl,需要注意的List<>集合问题~~~! 其他类型的集合可能也存在这样的问题,但是我没去测试,在写集合的时候一般List<>用的多点,所以经常碰 ...