2019.01.21 bzoj2989: 数列(二进制分组+主席树)
传送门
二进制分组入门题。
主席树写错调题2h+2h+2h+体验极差。
题意简述:给一堆点,支持加入一个点,询问有多少个点跟(x,y)(x,y)(x,y)曼哈顿距离不超过kkk。
思路:题目要求的是对于一个斜着的正方形的查询。
我们考虑转切比雪夫距离转成正常的正方形。
然后就变成了一个动态的二维数点问题。
这个时候已经可以上cdqcdqcdq分治+扫描线或者树套树切题啦。
然而还有一种叫做二进制分组的方法可以支持强制在线的操作。
我们考虑将修改分组,例如对于前19=16+2+119=16+2+119=16+2+1个修改操作可以把它拆成第111 ~ 161616个修改操作,第171717~181818个修改操作,第191919个修改操作这三组,每个组分别维护自己的答案,询问就从各个组分别询问之后把答案累加起来。
然后如果现在又来了第202020个操作,就需要把最后两个合并成一组,变成20=16+2+220=16+2+220=16+2+2,接着发现最后两个组都是222,又需要把最后两个合并成一组,变成20=16+420=16+420=16+4。
即我们模拟二进制数的进位来对修改操作进行组与组之间的合并
可以发现这样的时间复杂度是O(nlogn2)O(nlog_n^2)O(nlogn2)的,足以通过所有测试点。
最后提一下合并时候的处理方法:我们暴力删除最后一个组,然后重构倒数第二个组
代码:
#include<bits/stdc++.h>
#define ri register int
#define fi first
#define se second
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
const int N=2e5+5,K=1e7+5,lim=2e5,Maxn=100000;
int n,m,a[N],rt[20][N],tp=0;
struct segement_tree{
#define lc (son[p][0])
#define rc (son[p][1])
#define mid (l+r>>1)
int siz[K],son[K][2],stk[K],top;
bool vis[K];
segement_tree(){memset(siz,0,sizeof(siz)),memset(son,0,sizeof(son)),top=0;for(ri i=1;i<K;++i)stk[++top]=i,vis[i]=0;}
inline int newnode(){return vis[stk[top]]=1,stk[top--];}
inline void insert(int&p,int o,int l,int r,int k){
siz[p=newnode()]=siz[o]+1,lc=son[o][0],rc=son[o][1];
if(l==r)return;
k<=mid?insert(lc,son[o][0],l,mid,k):insert(rc,son[o][1],mid+1,r,k);
}
inline int query(int pl,int pr,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)return siz[pr]-siz[pl];
if(qr<=mid)return query(son[pl][0],son[pr][0],l,mid,ql,qr);
if(ql>mid)return query(son[pl][1],son[pr][1],mid+1,r,ql,qr);
return query(son[pl][0],son[pr][0],l,mid,ql,qr)+query(son[pl][1],son[pr][1],mid+1,r,ql,qr);
}
inline void delet(int&p){
if(!vis[p])return;
stk[++top]=p,vis[p]=0,delet(lc),delet(rc),siz[p]=0,p=0;
}
}T;
typedef pair<int,int> pii;
vector<pii>v[20];
inline void update(int x,int y){
v[++tp].push_back(pii(x,y));
T.insert(rt[tp][1],rt[tp][0],1,lim,y);
while(tp>1&&v[tp].size()==v[tp-1].size()){
int p1=0,p2=0;
vector<pii>tmp;
for(ri i=1;i<=v[tp].size();++i)T.delet(rt[tp][i]);
for(ri i=1;i<=v[tp-1].size();++i)T.delet(rt[tp-1][i]);
while(p1<v[tp-1].size()||p2<v[tp].size()){
if(p1<v[tp-1].size()&&(p2==v[tp].size()||v[tp-1][p1]<v[tp][p2]))tmp.push_back(v[tp-1][p1++]);
else tmp.push_back(v[tp][p2++]);
T.insert(rt[tp-1][p1+p2],rt[tp-1][p1+p2-1],1,lim,tmp[p1+p2-1].se);
}
v[tp-1]=tmp,v[tp].clear(),--tp;
}
}
inline int query(int x,int y,int k){
int ret=0;
for(ri p1,p2,i=1;i<=tp;++i){
p1=lower_bound(v[i].begin(),v[i].end(),pii(x-k,0))-v[i].begin();
p2=lower_bound(v[i].begin(),v[i].end(),pii(x+k,1e9))-v[i].begin();
ret+=T.query(rt[i][p1],rt[i][p2],1,lim,max(1,y-k),min(lim,y+k));
}
return ret;
}
int main(){
n=read(),m=read();
for(ri i=1;i<=n;++i)a[i]=read(),update(a[i]+i,a[i]-i+Maxn);
for(ri i=1,x,y;i<=m;++i){
char s[2];
scanf("%s",s);
x=read(),y=read();
if(s[0]=='M')a[x]=y,update(a[x]+x,a[x]-x+Maxn);
else cout<<query(a[x]+x,a[x]-x+Maxn,y)<<'\n';
}
return 0;
}
2019.01.21 bzoj2989: 数列(二进制分组+主席树)的更多相关文章
- [BZOJ 2989]数列(二进制分组+主席树)
[BZOJ 2989]数列(二进制分组+主席树) 题面 给定一个长度为n的正整数数列a[i]. 定义2个位置的graze值为两者位置差与数值差的和,即graze(x,y)=|x-y|+|a[x]-a[ ...
- bzoj2989&&4170数列——二进制分组+主席树
题意的转化挺巧妙的 可以联想到曼哈顿距离! 并且,所谓的修改还要查询历史版本,并且修改之间不动只算一次,不就是给平面上加一个点吗? 看成(x,a[x])的点 就是一个菱形区域 转切比雪夫距离,变成矩形 ...
- 2019.01.22 bzoj2874: 训练士兵(主席树)
传送门 题意简述:给出一个n∗mn*mn∗m的矩阵n,m≤1e8n,m\le1e8n,m≤1e8,支持矩形加,矩形求和,强制在线. 思路:第一眼二维动态开点线段树,上网去搜有没有这种做法发现会被卡时空 ...
- 2019.01.21 洛谷P3919 【模板】可持久化数组(主席树)
传送门 题意简述:支持在某个历史版本上修改某一个位置上的值,访问某个历史版本上的某一位置的值. 思路: 用主席树直接维护历史版本即可. 代码: #include<bits/stdc++.h> ...
- 2019.01.21 bzoj3674: 可持久化并查集加强版(主席树+并查集)
传送门 题意:维护可持久化并查集,支持在某个版本连边,回到某个版本,在某个版本 询问连通性. 思路: 我们用主席树维护并查集fafafa数组,由于要查询历史版本,因此不能够用路径压缩. 可以考虑另外一 ...
- 2019.01.21 bzoj1758: [Wc2010]重建计划(01分数规划+长链剖分+线段树)
传送门 长链剖分好题. 题意简述:给一棵树,问边数在[L,R][L,R][L,R]之间的路径权值和与边数之比的最大值. 思路: 用脚指头想都知道要01分数规划. 考虑怎么checkcheckcheck ...
- 2019.01.21 bzoj2441: [中山市选2011]小W的问题(树状数组+权值线段树)
传送门 数据结构优化计数菜题. 题意简述:给nnn个点问有多少个www型. www型的定义: 由5个不同的点组成,满足x1<x2<x3<x4<x5,x3>x1>x2 ...
- 2019.01.21 NOIP训练 可持久化序列【模板】(可持久化treap)
传送门 题意简述:支持在把某个数插入到某版本的第k个位置,删除某版本第k个数,询问第k个数. 思路:用可持久化treaptreaptreap维护区间第kkk个位置的数是啥就可以了. 代码
- 2019.01.21 NOIP训练 ak树(点分治)
传送门 题意简述:给一棵带权树,问在上面随机选两个点距离是4的倍数的概率. 思路: 由于总方案数为定值n2n^2n2,所以只用求总方案数. 这个跟聪聪可可差不多,可以用类似树形dpdpdp的方法边点分 ...
随机推荐
- goto,void,extern,sizeof分析
goto: 程序的质量与goto出现的次数成反比,禁用 goto的副作用:破环了程序的结构化的顺序执行的过程,它有可能会跳过程序的应该执行的一些步骤. void: 修饰函数返回值和参数 c语言中没有定 ...
- 利用crontab每天定时备份MySQL数据库
当数据库服务器建立并正式投入生产使用后,我们不得不担忧一个问题:当数据库遭到破坏后,怎样安然恢复到最后一次正常的状态,使得数据的损失达到最小. 我这里以本博客的wordpress数据为例,来讨论并实现 ...
- The following packages have unmet dependencies错误
当出现类似这类错误: The following packages have unmet dependencies: python-dev : Depends: python (= 2.7.5-5ub ...
- os & sys
os os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("dirname") 改变当前脚本工作目录:相当于shell下cd os.c ...
- Java_4 引用类型变量 Scanner与Random的使用
1.Scanner的使用 获得键盘输入的功能. 2.Random的使用 Random ran = new Random();//创建引用类型的变量 int number = ran.nextInt(1 ...
- Java08-java语法基础(七)构造方法
Java08-java语法基础(七)构造方法 一.构造方法 1.什么是构造方法? 构造方法(类方法)是一个方法名和类名相容的特殊的成员方法. 2.构造方法的作用? 当使用new关键字创建一个对象时,为 ...
- Windows到Linux的文件上传、下载
1.使用我们常用的Xshell登录工具,新建立一个远程会话,填写ip地址及用户名密码后,选择最下面的ZMODEM,填写下载的路径.加载的路径:2个路径可以一样也可以不一样: 2.在Linux主机上,安 ...
- how2j网站前端项目——天猫前端(第一次)学习笔记7
开始学习结算页面 结算页面分为3个部分学习:1.简单的头部和收货地址 2.较为复杂的确认订单信息 3.交互 一.简单的头部和收货地址 根据站长的图片,自己模仿着做了一下,刚开始没有想到填写信息的4个框 ...
- 运行SVO
安装与运行的所有文档:https://github.com/uzh-rpg/rpg_svo/wiki 有两种安装方式: 有ros:https://github.com/uzh-rpg/rpg_svo/ ...
- sqlserver数据库的物理存储格式和逻辑存储格式
物理存储结构: 数据库文件在磁盘上的存储形式: 主数据文件:*.mdf.用来存储数据库的启动信息.存储部分或全部的数据.整个的数据库只能有一个主数据文件 辅助数据文件:*.ndf.用于存储主数据文件未 ...