【BZOJ3821/UOJ46】玄学(二进制分组,线段树)

题面

BZOJ

UOJ

题解

呜,很好的题目啊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】玄学(二进制分组,线段树)的更多相关文章

  1. [BZOJ 2989]数列(二进制分组+主席树)

    [BZOJ 2989]数列(二进制分组+主席树) 题面 给定一个长度为n的正整数数列a[i]. 定义2个位置的graze值为两者位置差与数值差的和,即graze(x,y)=|x-y|+|a[x]-a[ ...

  2. 【BZOJ5294】[BJOI2018]二进制(线段树)

    [BZOJ5294][BJOI2018]二进制(线段树) 题面 BZOJ 洛谷 题解 二进制串在模\(3\)意义下,每一位代表的余数显然是\(121212\)这样子交替出现的. 其实换种方法看,就是\ ...

  3. bzoj2989&&4170数列——二进制分组+主席树

    题意的转化挺巧妙的 可以联想到曼哈顿距离! 并且,所谓的修改还要查询历史版本,并且修改之间不动只算一次,不就是给平面上加一个点吗? 看成(x,a[x])的点 就是一个菱形区域 转切比雪夫距离,变成矩形 ...

  4. UOJ46 【清华集训2014】玄学 【时间线段树】

    题目链接:UOJ 这题的时间线段树非常的妙. 对时间建立线段树,修改的时候在后面加,每当填满一个节点之后就合并进它的父亲. 对于一个节点维护序列,发现这是一个分段函数,合并就是归并排序.于是就形成了差 ...

  5. 2019.02.12 bzoj5294: [Bjoi2018]二进制(线段树)

    传送门 题意简述: 给出一个长度为nnn的二进制串. 你需要支持如下操作: 修改每个位置:1变0,0变1 询问对于一个区间的子二进制串有多少满足重排之后转回十进制值为333的倍数(允许前导000). ...

  6. 2019.01.21 bzoj2989: 数列(二进制分组+主席树)

    传送门 二进制分组入门题. 主席树写错调题2h+2h+2h+体验极差. 题意简述:给一堆点,支持加入一个点,询问有多少个点跟(x,y)(x,y)(x,y)曼哈顿距离不超过kkk. 思路:题目要求的是对 ...

  7. Multidimensional Queries(二进制枚举+线段树+Educational Codeforces Round 56 (Rated for Div. 2))

    题目链接: https://codeforces.com/contest/1093/problem/G 题目: 题意: 在k维空间中有n个点,每次给你两种操作,一种是将某一个点的坐标改为另一个坐标,一 ...

  8. 洛谷P4428二进制 [BJOI2018] 线段树

    正解:线段树 解题报告: 传送门! 话说开始看到这题的时候我想得hin简单 因为关于%3有个性质就是说一个数的各个位数之和%3=这个数%3嘛,小学基础知识? 我就想着,就直接建一棵树,只是这棵树要用个 ...

  9. BZOJ5294 [BJOI2018] 二进制 【线段树】

    BJOI的题目感觉有点难写 题目分析: 首先推一波结论.接下来的一切都在模3意义下 现在我们将二进制位重组,不难发现的是2^0≡1,2^1≡2,2^2≡1,2^3≡2....所以我们考虑这样的式子 2 ...

  10. BZOJ5294 BJOI2018二进制(线段树)

    二进制数能被3整除相当于奇数.偶数位上1的个数模3同余.那么如果有偶数个1,一定存在重排方案使其合法:否则则要求至少有两个0且至少有3个1,这样可以给奇数位单独安排3个1. 考虑线段树维护区间内的一堆 ...

随机推荐

  1. SDP服务搜索流程源码分析

    BREDR的设备 在进行配对完成之后,进行;连接之前都要进行服务的搜索,服务搜索走的流程是SDP,这篇文章就分析一下,bluedroid中SDP的代码流程,我们从配对完成的回调函数开始分析: /*** ...

  2. GATT服务搜索流程(一)

    GATT的规范阅读起来还是比较简答, 但是这样的规范在代码上是如何实现的呢?下面就分析一下bluedroid 协议栈关于GATT的代码流程. BLE的设备都是在SMP之后进行ATT的流程的交互.从代码 ...

  3. 手机APP自动化之uiautomator2 +python3 UI自动化

    题记: 之前一直用APPium直到用安卓9.0  发现uiautomatorviewer不支持安卓 9.0,点击截屏按钮 一直报错,百度很久解决方法都不可以,偶然间看见有人推荐:uiautomator ...

  4. mac系统下修复第三方Python包bug

    发现问题 今天在github上fork了CI 3.x的中文手册,按照README文档一步步进行Sphinx和相关工具的安装,最终build生成html版手册.操作到第6步执行`make html`的时 ...

  5. 网络:OSPF理解

    OSPF(开放最短路径优先)协议使用Dijkstra算法,常见的版本有:OSPFv2.OSPFv3等.以下主要介绍OSPFv2,OSPFv3是面向IPv6的且不兼容IPv4. 1.工作过程: 1)每台 ...

  6. 防止重复提交demo

    利用session防止重复提交 思路: 前端控制:在点击提交按钮后设置按钮不可用. 后台控制:利用session,在初次进入表单页面的时候前生成一个随机token,将token保存到session并返 ...

  7. Maven的课堂笔记1

    1 什么是maven? Maven是一个跨平台的项目管理工具,主要用于基于java平台的项目构建,依赖管理. Clean  compile  test  package  install   run ...

  8. Java使用HTTPClient3.0.1开发的公众平台消息模板的推送功能

    package com.company.product.manager.busniess.impl; import java.io.IOException;import java.nio.charse ...

  9. Hacked VisualSVN Server by PHP to allow user change password

    index.php <?php$username = $_SERVER["PHP_AUTH_USER"]; //经过 AuthType Basic 认证的用户名$authed ...

  10. node的consoidate的插件统一

    使用consolidate.ejs.的这种形式. let express = require('express'); let app = express(); app.set('views','返回的 ...