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 ...
随机推荐
- 【JVM.12】线程安全与锁优化
一.概述 面向过程的编程思想极大地提升了现代软件开发的生产效率和软件可以达到的规模,但是现实世界与计算机世界之间不可避免地存在一些差异,本节就如何保证并发的正确性和如何实现线程安全讲起. 二.线程安全 ...
- Nginx报错: "Too many open files accept" 和 "could not build the server_names_hash"
一.访问Nginx时,报错:"accept() failed (24: Too many open files)"原因时:nginx的连接数超过了系统设定的最大值造成的. 处理办法 ...
- 705 B. Spider Man
传送门 [http://codeforces.com/contest/705/problem/B] 题意 这题意看原文的真tm难懂Woc,但结合样例就知道大概意思了 两个轮流分环,可以这么理解两个人轮 ...
- 《Linux内核设计与分析》第六周读书笔记——第三章
<Linux内核设计与实现>第六周读书笔记——第三章 20135301张忻估算学习时间:共2.5小时读书:2.0代码:0作业:0博客:0.5实际学习时间:共3.0小时读书:2.0代码:0作 ...
- “using NoSQL” under MySQL
https://dev.mysql.com/doc/refman/5.7/en/document-store.html https://dev.mysql.com/doc/refman/5.7/en/ ...
- Mysql 5.7.21 设置主从库同步
主从复制条件: Mysql 单机多实例安装参考Mysql 5.7.21 设置主从库同步 下面的操作是多实例主从复制,3306为主库,3307为从库. 主库要开启log-bin,主库和从库的server ...
- 面象对象设计原则之二:开放封闭原则(Open-Closed Principle, OCP)
开闭原则是面向对象的可复用设计的第一块基石,它是最重要的面向对象设计原则.开闭原则由Bertrand Meyer于1988年提出,其定义如下: 开闭原则(Open-Closed Principle, ...
- Oracle 控制文件管理
控制文件是一个很小的二进制文件(10MB左右),含有数据库结构信息,包括数据文件和日志文件信息.控制文件在数据库创建时被自动创建,并在数据库发生物理变数时更新.控制文件被不断更新,在任何时候都要保证控 ...
- [转帖]服务器操作系统应该选择 Debian/Ubuntu 还是 CentOS?
来源:https://www.zhihu.com/question/19599986 作者: https://www.zhihu.com/people/yuan-hao-yang/answers IT ...
- Java之反射举例
package reflection; import bean.User; public class ReflectionDemo { public static void main(String[] ...