bzoj2989&&4170数列——二进制分组+主席树
题意的转化挺巧妙的
可以联想到曼哈顿距离!
并且,所谓的修改还要查询历史版本,并且修改之间不动只算一次,不就是给平面上加一个点吗?
看成(x,a[x])的点
就是一个菱形区域
转切比雪夫距离,变成矩形区域
所以
平面单点加,矩形查询和
1.cdq分治
2.树套树(离散化都不用)
3.二进制分组+主席树
这里,大炮打蚊子,用二进制分组来写
加入的点按操作二进制分组,每个组用主席树维护这个平面,查询在logn上查询,合并暴力重构,256MB又没有删除,所以重构完了把原来的树垃圾回收
注意:
主席树垃圾回收,从最后一个根开始,一个点不能删除两次,所以共用点打die标记,之后搜到返回即可。
代码:
写得很丑
其实不用vector,可以开数组,记录每个组的范围。每次sort,然后建树。
#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^'0')
#define mid ((l+r)>>1)
#define fi first
#define se second
#define mp(a,b) make_pair(a,b)
using namespace std;
typedef long long ll;
il void rd(int &x){
char ch;x=;bool fl=false;
while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
for(x=numb;isdigit(ch=getchar());x=x*+numb);
(fl==true)&&(x=-x);
}
namespace Miracle{
const int N=+;
const int U=;
int n,q;
pair<int,int>a[N];
int b[N];
char ch[];
struct node{
int ls,rs;
int sum;
void clear(){
ls=rs=sum=;
}
}t[*];
int tot;
int sta[N],top;
int del[*],dc;
bool die[*];
int nc(){
int r=dc?del[dc--]:++tot;
die[r]=;
t[r].clear();
// cout<<" r "<<r<<" "<<t[r].sum<<" "<<t[r].ls<<" "<<t[r].rs<<endl;
return r;
//return ++tot;
}
int cnt;
vector<pair<int,int> >mem[N];
vector<int>rt[N],pos[N];
bool cmp(pair<int,int>a,pair<int,int> b){//a<b?
if(a.fi==b.fi) return a.se<b.se;
return a.fi<b.fi;
}
void merge(int i,int j){
vector<pair<int,int> >tmp;
int l=,r=;
for(reg k=;k<=(int)mem[i].size()+(int)mem[j].size();++k){
if(l>=(int)mem[i].size()){
tmp.push_back(mem[j][r++]);
}else if(r>=(int)mem[j].size()){
tmp.push_back(mem[i][l++]);
}else if(cmp(mem[i][l],mem[j][r])){
tmp.push_back(mem[i][l++]);
}else{
tmp.push_back(mem[j][r++]);
}
}
mem[i]=tmp;
}
void upda(int &x,int y,int l,int r,int p){
if(!x) x=nc();
t[x].sum=t[y].sum+;
if(l==r){return;}
if(p<=mid){
t[x].rs=t[y].rs;upda(t[x].ls,t[y].ls,l,mid,p);
}else{
t[x].ls=t[y].ls;upda(t[x].rs,t[y].rs,mid+,r,p);
}
}
void remove(int x){
if(!x||die[x]) return;
remove(t[x].ls);remove(t[x].rs);
t[x].clear();
die[x]=;
del[++dc]=x;
}
int query(int x,int y,int l,int r,int L,int R){
//cout<<" query "<<x<<" "<<y<<" "<<l<<" "<<r<<" goal "<<L<<" "<<R<<endl;
//cout<<" sum "<<t[x].sum<<" and "<<t[y].sum<<endl;
if(L<=l&&r<=R){
return t[x].sum-t[y].sum;
}
int ret=;
if(L<=mid) ret+=query(t[x].ls,t[y].ls,l,mid,L,R);
if(mid<R) ret+=query(t[x].rs,t[y].rs,mid+,r,L,R);
return ret;
}
void bing(int A,int B){
//cout<<" merge "<<A<<" "<<B<<endl;
// cout<<mem[A].size()<<" and "<<mem[B].size()<<endl;
for(reg i=rt[A].size()-;i>=;--i)
remove(rt[A][i]);
for(reg i=rt[B].size()-;i>=;--i)
remove(rt[B][i]);
// cout<<" guibing "<<endl;
merge(A,B); rt[A].clear();pos[A].clear();
for(reg i=;i<(int)mem[A].size();++i){
if(i==){
rt[A].push_back();pos[A].push_back(mem[A][i].fi);
upda(rt[A][],,-U,U,mem[A][i].se);
}else{
if(mem[A][i-].fi==mem[A][i].fi){
int tmp=rt[A][rt[A].size()-];
rt[A][rt[A].size()-]=;
upda(rt[A][rt[A].size()-],tmp,-U,U,mem[A][i].se);
}else{
rt[A].push_back();pos[A].push_back(mem[A][i].fi);
upda(rt[A][rt[A].size()-],rt[A][rt[A].size()-],-U,U,mem[A][i].se);
}
}
}
}
int calc(int x1,int y1,int x2,int y2){
int ret=;
//cout<<" seventy-five "<<t[75].sum<<endl;
for(reg i=;i<=top;++i){
int id=sta[i];
// cout<<" id "<<id<<" mem "<<mem[id].size()<<" pos "<<pos[id].size()<<endl;
// cout<<" seventy-five "<<t[75].sum<<endl;
int k1=lower_bound(pos[id].begin(),pos[id].end(),y1)-pos[id].begin();
--k1;
int k2=upper_bound(pos[id].begin(),pos[id].end(),y2)-pos[id].begin();
--k2;
// cout<<k1<<" and "<<k2<<endl;
// cout<<" seventy-five "<<t[75].sum<<endl;
k1=k1<?:rt[id][k1];
k2=k2<?:rt[id][k2];
ret+=query(k2,k1,-U,U,x1,x2);
// cout<<" seventy-five "<<t[75].sum<<endl;
}
return ret;
}
int main(){
rd(n);rd(q);
int x;
for(reg i=;i<=n;++i){
rd(x);a[i]=mp(i+x,i-x);
b[i]=x;
}
// cout<<cmp(mp(3,-1),mp(6,-2))<<endl;
sort(a+,a+n+,cmp);
for(reg i=;i<=n;++i){
//cout<<"("<<a[i].se<<","<<a[i].fi<<")"<<endl;
++cnt;
mem[cnt].push_back(a[i]);
rt[cnt].push_back();
pos[cnt].push_back(a[i].fi);
upda(rt[cnt][],,-U,U,a[i].se);
sta[++top]=cnt;
while(top>&&mem[sta[top]].size()==mem[sta[top-]].size()){
bing(sta[top-],sta[top]);
--top;
}
}
// cout<<cnt<<" "<<top<<endl;
int k;
while(q--){
scanf("%s",ch+);
rd(x);rd(k);
if(ch[]=='Q'){
// cout<<" seventy-five "<<t[75].sum<<endl;
printf("%d\n",calc(x-b[x]-k,x+b[x]-k,x-b[x]+k,x+b[x]+k));
// cout<<" seventy-five "<<t[75].sum<<endl;
}else{
++cnt;
mem[cnt].push_back(mp(x+k,x-k));
rt[cnt].push_back();
pos[cnt].push_back(x+k);
upda(rt[cnt][],,-U,U,x-k);
sta[++top]=cnt;
while(top>&&mem[sta[top]].size()==mem[sta[top-]].size()){
bing(sta[top-],sta[top]);
--top;
}
b[x]=k;
/// cout<<" seventy-five "<<t[75].sum<<endl;
// cout<<cnt<<" "<<top<<endl;
}
}
return ;
} }
signed main(){
// freopen("data.in","r",stdin);
// freopen("my.out","w",stdout);
Miracle::main();
return ;
} /*
Author: *Miracle*
Date: 2019/2/24 9:42:39
*/
bzoj2989&&4170数列——二进制分组+主席树的更多相关文章
- [BZOJ 2989]数列(二进制分组+主席树)
[BZOJ 2989]数列(二进制分组+主席树) 题面 给定一个长度为n的正整数数列a[i]. 定义2个位置的graze值为两者位置差与数值差的和,即graze(x,y)=|x-y|+|a[x]-a[ ...
- 2019.01.21 bzoj2989: 数列(二进制分组+主席树)
传送门 二进制分组入门题. 主席树写错调题2h+2h+2h+体验极差. 题意简述:给一堆点,支持加入一个点,询问有多少个点跟(x,y)(x,y)(x,y)曼哈顿距离不超过kkk. 思路:题目要求的是对 ...
- Dynamic Rankings ZOJ - 2112(主席树+树状数组)
The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with t ...
- 【BZOJ2989】数列(二进制分组,主席树)
[BZOJ2989]数列(二进制分组,主席树) 题面 BZOJ 权限题啊... Description 给定一个长度为n的正整数数列a[i]. 定义2个位置的graze值为两者位置差与数值差的和,即g ...
- BZOJ2989 数列(二进制分组)
这题其实可以cdq分治做,但是如果强制在线的话,这里有个牛逼方法叫二进制分组. 它的基本思想是把修改操作按二进制分组,遇到修改就在尾部加一个,并与之前的合并,比如之前有23(16+4+2+1)个,加了 ...
- UOJ46. 【清华集训2014】玄学 [线段树,二进制分组]
UOJ 思路 模拟赛出了这题,结果我没学过二进制分组--一波主席树然后空间就爆炸了-- 用线段树维护时间序列,每个节点维护\(a_i\to x_i\times a_i+b_i,i\in [1,n]\) ...
- CDOJ 1104 求两个数列的子列的交集 查询区间小于A的数有多少个 主席树
求两个数列的子列的交集 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/1104 ...
- 【BZOJ3821/UOJ46】玄学(二进制分组,线段树)
[BZOJ3821/UOJ46]玄学(二进制分组,线段树) 题面 BZOJ UOJ 题解 呜,很好的题目啊QwQ. 离线做法大概可以线段树分治,或者直接点记录左右两次操作时的结果,两个除一下就可以直接 ...
- Codeforces 960 二进制构造子序列 完全二叉树shift模拟 主席树/MAP DP
A #include <bits/stdc++.h> #define PI acos(-1.0) #define mem(a,b) memset((a),b,sizeof(a)) #def ...
随机推荐
- 开发CMDB系统
背景: 在现网环境中服务器多了每天服务器的配置 情况我们很难记住,当某台服务器硬件配置变化后可以第一时间了解,某台服务器出现问题时可以快速定位机架位置,之前都是excel文档,要查某项数据时极不方便. ...
- 树莓派Opencv张正友棋盘标定法
make.Makefile cc = gcc #最简易的makefile文件,这个可以用来进行文件之间的简易构建和链接,生成我们所需要的执行文件: prom = calc deps = $(shell ...
- HTML5-indexedDB使用常见错误总结
indexedDB使用过程中常常会出现以下错误: Failed to execute ‘createObjectStore’ on ‘IDBDatabase’: The database is not ...
- C_数据结构_循环实现求阶乘
# include <stdio.h> int main(void) { int val; printf("请输入一个数字:"); printf("val = ...
- JDK+JAVA+maven+IDEA
JDK+JAVA https://jingyan.baidu.com/article/6dad5075d1dc40a123e36ea3.html maven+IDEA http://blog.csdn ...
- 《Metasploit渗透测试魔鬼训练营》第一章读书笔记
第1章 魔鬼训练营--初识Metasploit 20135301 1.1 什么是渗透测试 1.1.1 渗透测试的起源与定义 如果大家对军事感兴趣,会知道各国军队每年都会组织一些军事演习来锻炼军队的攻防 ...
- 第二个spring,第三天
陈志棚:成绩的统筹 李天麟:界面音乐 徐侃:代码算法 给位组员继续的完成分配任务.
- 关于<T> T[] toArray(T[] a) 方法
http://mopishv0.blog.163.com/blog/static/5445593220101016102129741/ private List<String> uploa ...
- 转载 linux常用的监控命令工具
工具 简单介绍top 查看进程活动状态以及一些系统状况vmstat 查看系统状态.硬件和系统信息等iostat 查看CPU 负载,硬盘状况sar 综合工具,查看系统状况mpstat 查看多处理器状况n ...
- 序列化与反序列化,json,pickle,xml,shelve,configparser模块
序列化与反序列化 什么是序列化?序列化就是将内存中的数据结构转换成一种中间格式存储到硬盘或者基于网络传输.反序列化就是将硬盘中或者网络中传来的一种数据格式转换成内存中数据结构. 为什么要有? 1.可以 ...