题意的转化挺巧妙的

可以联想到曼哈顿距离!

并且,所谓的修改还要查询历史版本,并且修改之间不动只算一次,不就是给平面上加一个点吗?

看成(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数列——二进制分组+主席树的更多相关文章

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

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

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

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

  3. Dynamic Rankings ZOJ - 2112(主席树+树状数组)

    The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with t ...

  4. 【BZOJ2989】数列(二进制分组,主席树)

    [BZOJ2989]数列(二进制分组,主席树) 题面 BZOJ 权限题啊... Description 给定一个长度为n的正整数数列a[i]. 定义2个位置的graze值为两者位置差与数值差的和,即g ...

  5. BZOJ2989 数列(二进制分组)

    这题其实可以cdq分治做,但是如果强制在线的话,这里有个牛逼方法叫二进制分组. 它的基本思想是把修改操作按二进制分组,遇到修改就在尾部加一个,并与之前的合并,比如之前有23(16+4+2+1)个,加了 ...

  6. UOJ46. 【清华集训2014】玄学 [线段树,二进制分组]

    UOJ 思路 模拟赛出了这题,结果我没学过二进制分组--一波主席树然后空间就爆炸了-- 用线段树维护时间序列,每个节点维护\(a_i\to x_i\times a_i+b_i,i\in [1,n]\) ...

  7. CDOJ 1104 求两个数列的子列的交集 查询区间小于A的数有多少个 主席树

    求两个数列的子列的交集 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/1104 ...

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

    [BZOJ3821/UOJ46]玄学(二进制分组,线段树) 题面 BZOJ UOJ 题解 呜,很好的题目啊QwQ. 离线做法大概可以线段树分治,或者直接点记录左右两次操作时的结果,两个除一下就可以直接 ...

  9. 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 ...

随机推荐

  1. Nginx挂载维护页或返回自定义响应信息

    在服务停机升级或者服务暂不可用时,往往希望能够返回给用户更为明确和友好的响应信息.可以通过修改nginx配置文件,达到返回自定义信息的效果.有如下几种配置方式: (1)Nginx接收到的所有请求,都返 ...

  2. 基于RC4加密算法的图像加密

    基于RC4加密算法的图像加密 某课程的一个大作业内容,对图像加密.项目地址:https://gitee.com/jerry323/RC4_picture 这里使用的是RC4(流.对称)加密算法,算法流 ...

  3. C-代码笔记-输入输出

    .ACSII 字符实质和整数存储方式相同 //2018年9月16日01:35:54 # include <stdio.h> int main(void) { '; // printf(&q ...

  4. 置换群 Burnside引理 Pólya定理(Polya)

    置换群 设\(N\)表示组合方案集合.如用两种颜色染四个格子,则\(N=\{\{0,0,0,0\},\{0,0,0,1\},\{0,0,1,0\},...,\{1,1,1,1\}\}\),\(|N|= ...

  5. wordcount程序中的应用与拓展

    设计思路: 关键是思路,首先知道 单词, 行,字符, 他们有什么特点: 1.单词,标准的是遇到空格后,单词数,自动加一. 2.行是以\n结束的, 也就是说, 遇到\n行数加一,当然也视你的操作系统而言 ...

  6. Echarts中graph类型的运用求教

    以下是百度Echarts官网上关系图的源码,但是这个关系图的node节点和edge都是静态文件里规定好的,我现在想动态实现,点击其中一个节点A然后新产生一个新节点B,并且有A和B之间的edge,就类似 ...

  7. Linux内核分析——第四章 进程调度

    第四章 进程调度 4.1 多任务 1.多任务操作系统就是能同时并发的交互执行多个进程的操作系统. 2.多任务操作系统使多个进程处于堵塞或者睡眠状态,实际不被投入执行,这些任务尽管位于内存,但是并不处于 ...

  8. <四则运算>第二次冲刺

    这一次冲刺的主要内容是完善我们的界面,是我们的APP界面更规划更标准一点, 然后还要添加一些新算法. 距离客户的需求已经一半了. 代码正在完善中,稍后上传...

  9. 软件工程(GZSD2015)学生博客列表

    2015年贵州师范大学软件工程课程学生博客列表 陈小丽 郑倩 唐洁 周娟 李利思 肖俊 罗文豪 周静 徐明艳 毛涛 邓洪虹 岳庆 李盼 安坤 何亚 涂江凤 张义平 杨明颢 杨家堂 胡贵玲 寿克霞 吴明 ...

  10. Repair U Disk logo unvisiable in task bar on windows XP

    Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersio ...