UOJ46 玄学
题目
一个比较自然的想法是线段树维护二进制分组。
因为我们询问的是一段连续的操作的积,所以我们可以建一棵线段树,每个节点存储当前区间各个操作的积。
这里的操作的积指的是把一系列操作做完之后区间每个位置的变换。因为有很多连续的变换是一样的所以我们可以把它们缩起来。
因为我们知道\(k\)个操作最多会把整个区间划为\(2k+1\)段,所以所有节点的区间的总数是\(O(n\log n)\)级别的。
而合并两个线段树节点的操作可以使用归并排序。
然后我们查询就可以找到对应的\(log\ n\)的线段树上的节点,然后在每个节点存储的区间中二分找到查询的位置所在的区间,然后把所有查询到的变换乘起来就行了。
还要注意一件事情:
因为是强制在线,我们的操作也是一个个给出而不是一开始全部给出,所以我们需要一开始先建出空的线段树,然后新加进来一个操作,我们就把它插入到线段树上对应的\(log\ n\)个节点中去,同时pushup一下。
#include<bits/stdc++.h>
#define ep emplace_back
#define pi pair<int,int>
#define fi first
#define se second
#define ls p<<1
#define rs p<<1|1
using namespace std;
namespace IO
{
char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[15],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
void Put(char x){*oS++=x;if(oS==oT)Flush();}
int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
void write(int x){int top=0;if(!x)Put('0');while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put('\n');}
}
using namespace IO;
int max(int a,int b){return a>b? a:b;}
const int N=100007;
int n,m,q,ison,v[N],L[N<<2],R[N<<2];pi e(1,0),f;struct node{int l,r;pi x;node(int a=0,int b=0,pi c=e){l=a,r=b,x=c;}};
vector<int>id[N];vector<node>t[N<<2],tmp;
int operator<(node a,node b){return a.r<b.r;}
pi mul(pi a,pi b){return pi(1ll*a.fi*b.fi%m,(1ll*a.se*b.fi+b.se)%m);}
vector<node>merge(vector<node>a,vector<node>b)
{
vector<node>c;
for(int i=0,j=0;i<(int)a.size()||j<(int)b.size();)
if(a[i].r==b[j].r) c.ep(max(a[i].l,b[j].l),a[i].r,mul(a[i].x,b[j].x)),++i,++j;
else if(a[i].r<b[j].r) c.ep(max(a[i].l,b[j].l),a[i].r,mul(a[i].x,b[j].x)),++i;
else c.ep(max(a[i].l,b[j].l),b[j].r,mul(a[i].x,b[j].x)),++j;
return c;
}
void build(int p,int l,int r)
{
id[r].ep(p),L[p]=l,R[p]=r,t[p].ep(1,n,e);
if(l==r) return ;int mid=(l+r)>>1;
build(ls,l,mid),build(rs,mid+1,r);
}
pi query(int p,int l,int r,int x)
{
if(l<=L[p]&&R[p]<=r) return lower_bound(t[p].begin(),t[p].end(),(node){0,x,e})->x;
int mid=(L[p]+R[p])>>1;
return mul((l<=mid? query(ls,l,r,x):e),(r>mid? query(rs,l,r,x):e));
}
int main()
{
ison=read()&1,n=read(),m=read();
for(int i=1;i<=n;++i) v[i]=read();
q=read(),build(1,1,min(q,100000));
for(int i=1;i<=min(q,100000);++i) reverse(id[i].begin(),id[i].end());
for(int T=0,l,r,a,b,ans=0;q;--q)
{
if(read()==1)
{
l=read(),r=read(),a=read(),b=read(),tmp.clear(),++T;
if(ison) l^=ans,r^=ans;
if(l>1) tmp.ep(1,l-1,e);
tmp.ep(l,r,pi(a,b));
if(r<n) tmp.ep(r+1,n,e);
for(int p:id[T]) t[p]=L[p]==R[p]? merge(t[p],tmp):merge(t[ls],t[rs]);
}
else
{
l=read(),r=read(),a=read();
if(ison) l^=ans,r^=ans,a^=ans;
f=query(1,l,r,a),write(ans=(1ll*v[a]*f.fi+f.se)%m);
}
}
return Flush(),0;
}
UOJ46 玄学的更多相关文章
- uoj46玄学
复杂度辣鸡没人权 疯狂爆oj 感觉要被众多uoj用户骂了 #include <bits/stdc++.h> #define ll long long #define LS ls[now]? ...
- 【BZOJ3821/UOJ46】玄学(二进制分组,线段树)
[BZOJ3821/UOJ46]玄学(二进制分组,线段树) 题面 BZOJ UOJ 题解 呜,很好的题目啊QwQ. 离线做法大概可以线段树分治,或者直接点记录左右两次操作时的结果,两个除一下就可以直接 ...
- [UOJ46][清华集训2014]玄学
uoj description 给出\(n\)个变换,第\(i\)个变换是将区间中\(l_i,r_i\)的数\(x\)变成\((a_ix+b_i)\mod m\). 每次会新增一个变换,或者查询询问如 ...
- UOJ46. 【清华集训2014】玄学
传送门 Sol 考虑对于操作时间建立线段树,二进制分组 那么现在主要的问题就是怎么合并信息 你发现一个性质,就是每个修改只会在整个区间内增加两个端点 那么我们二进制分组可以得到每个区间内最多只有区间长 ...
- UOJ46. 【清华集训2014】玄学 [线段树,二进制分组]
UOJ 思路 模拟赛出了这题,结果我没学过二进制分组--一波主席树然后空间就爆炸了-- 用线段树维护时间序列,每个节点维护\(a_i\to x_i\times a_i+b_i,i\in [1,n]\) ...
- UOJ46 清华集训2014玄学(线段树)
注意到操作有结合律,容易想到用一个矩形表示第i次操作对第j个位置的数的影响.那么修改是单行内的区间修改,而查询是单列内的区间查询.这样二维线段树上以列为外层行为内层直接打标记就可以维护.然后就喜闻乐见 ...
- UOJ46 【清华集训2014】玄学 【时间线段树】
题目链接:UOJ 这题的时间线段树非常的妙. 对时间建立线段树,修改的时候在后面加,每当填满一个节点之后就合并进它的父亲. 对于一个节点维护序列,发现这是一个分段函数,合并就是归并排序.于是就形成了差 ...
- 洛谷P2832 行路难 分析+题解代码【玄学最短路】
洛谷P2832 行路难 分析+题解代码[玄学最短路] 题目背景: 小X来到了山区,领略山林之乐.在他乐以忘忧之时,他突然发现,开学迫在眉睫 题目描述: 山区有n座山.山之间有m条羊肠小道,每条连接两座 ...
- C++玄学预编译优化
#pragma GCC diagnostic error "-std=c++11" #pragma GCC optimize("-fdelete-null-pointer ...
随机推荐
- 火焰图分析CPU性能问题
1.找出应用程序或内核消耗CPU的PID 2.执行perf record 命令,记录该PID的行为 perf record -a -g -p 14851 -- sleep 30 --30秒后退出 3. ...
- Git与Repo 的使用
一.Linux常用命令 pwd 用于显示工作目录,执行pwd指令可立刻得知您目前所在的工作目录的绝对路径名称. chmod 用来变更文件或目录的权限. > ...
- C++入门经典-例7.4-类的静态成员,我们共有一个地球
1:静态数据在程序开始时即获得空间,直到程序结束后才被收回.静态数据可以声明在函数体内,也可以声明在函数体外. 类中的静态成员与非静态成员有很大区别.从使用上来将,调用静态成员不需要实例化对象,而是以 ...
- Leetcode题目33.搜索旋转排序数组(中等)
题目描述: 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定的目标值,如果数组中存在 ...
- Location of Docker images in all Operating Systems (Linux, Windows, Redhat, Mac OS X)
原文:http://www.scmgalaxy.com/tutorials/location-of-dockers-images-in-all-operating-systems/ Location ...
- LeetCode 90. 子集 II(Subsets II)
题目描述 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: [1,2,2] 输出: [ [2], [1], [1,2,2 ...
- python - 技术提高要点之一,函数式编程,性能,测试和编码规范
摘自:http://www.cnblogs.com/kaituorensheng/p/4516983.html 函数式编程 命令式的编程风格已经成为事实上的标准.命令式编程的程序是由一些描述状态转变的 ...
- CentOS6.8安装Oracle11g
===== 这中间还有很多细节问题该文档中并没有说明和指出: 1.如/tmp目录必须单独分出来,不然oracle在以后的使用中会逐渐变慢 2.官网说的512M内存即可,这里纠正下,如果只是测试安装那还 ...
- 由STL map调用clear后,内存不返还给操作系统的问题出发,探讨glibc malloc/free行为(转)
1. 问题 我们的程序有几十个线程,每个线程拥有一个std::map,每个线程都要向自己的std::map中插入大量的数据,但每个数据只有几十字节:当使用完std::map,调用map.clear() ...
- 学习使用Jmeter做压力测试(一)--压力测试基本概念
学习使用Jmeter做压力测试(一)--压力测试基本概念 一.性能测试的概念 性能测试是通过自动化的测试工具模拟多种正常峰值及异常负载条件来对系统的各项性能指标进行测试.负载测试和压力测试都属于性能测 ...