【BZOJ2989】数列(二进制分组,主席树)
【BZOJ2989】数列(二进制分组,主席树)
题面
BZOJ
权限题啊。。。
Description
给定一个长度为n的正整数数列a[i]。
定义2个位置的graze值为两者位置差与数值差的和,即graze(x,y)=|x-y|+|a[x]-a[y]|。
2种操作(k都是正整数):
1.Modify x k:将第x个数的值修改为k。
2.Query x k:询问有几个i满足graze(x,i)<=k。因为可持久化数据结构的流行,询问不仅要考虑当前数列,还要
考虑任意历史版本,即统计任意位置上出现过的任意数值与当前的a[x]的graze值<=k的对数。(某位置多次修改为
同样的数值,按多次统计)
Input
第1行两个整数n,q。分别表示数列长度和操作数。
第2行n个正整数,代表初始数列。
第3--q+2行每行一个操作。
Output
对于每次询问操作,输出一个非负整数表示答案
Sample Input
3 5
2 4 3
Query 2 2
Modify 1 3
Query 2 2
Modify 1 2
Query 1 1
Sample Output
2
3
3
HINT
N<=60000 修改操作数<=40000 询问<=50000 Max{a[i]}含修改<=100000
题解
其实这题并不需要支持强制在线,所以二进制分组被CDQ分治打爆了。
我们对于每个组开主席树,每次询问相当于在每个组内都查询一次求和,
好暴力啊。。。。。
然而复杂度\(O(nlog^2n)\),惨遭\(CDQ\)分治打爆。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
#define ll long long
#define inf 1000000000
#define MAX 200200
#define MAXNODE MAX<<5
#define py 65000
#define N 200000
#define pi pair<int,int>
#define mp make_pair
#define pb push_back
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;
}
char ch[20];
struct Node{int ls,rs,v;}t[MAXNODE];
int top,St[MAXNODE];bool vis[MAXNODE];
int NewNode(){vis[St[top]]=true;return St[top--];}
int Query(int A,int B,int l,int r,int L,int R)
{
	if(L<=l&&r<=R)return t[B].v-t[A].v;
	int mid=(l+r)>>1,ret=0;
	if(L<=mid)ret+=Query(t[A].ls,t[B].ls,l,mid,L,R);
	if(R>mid)ret+=Query(t[A].rs,t[B].rs,mid+1,r,L,R);
	return ret;
}
void modify(int &x,int ff,int l,int r,int p)
{
	t[x=NewNode()]=t[ff];t[x].v+=1;if(l==r)return;
	int mid=(l+r)>>1;
	if(p<=mid)modify(t[x].ls,t[ff].ls,l,mid,p);
	else modify(t[x].rs,t[ff].rs,mid+1,r,p);
}
void Del(int &x)
{
	if(!vis[x])return;
	St[++top]=x;vis[x]=false;
	Del(t[x].ls);Del(t[x].rs);
	t[x].v=0;x=0;
}
vector<pi> v[20];
int rt[20][MAX],Top;
void insert(int x,int y)
{
	v[++Top].pb(mp(x,y));
	modify(rt[Top][1],rt[Top][0],1,N,y);
	while(Top>1&&v[Top-1].size()==v[Top].size())
	{
		int t1=0,t2=0;vector<pi> t;
		for(int i=1;i<=v[Top-1].size();++i)Del(rt[Top-1][i]);
		for(int i=1;i<=v[Top].size();++i)Del(rt[Top][i]);
		while(t1<v[Top-1].size()||t2<v[Top].size())
		{
			if(t1<v[Top-1].size()&&(t2==v[Top].size()||v[Top-1][t1]<v[Top][t2]))
				t.pb(v[Top-1][t1++]);
			else t.pb(v[Top][t2++]);
			modify(rt[Top-1][t1+t2],rt[Top-1][t1+t2-1],1,N,t[t1+t2-1].second);
		}
		v[Top-1]=t;v[Top].clear();Top--;
	}
}
int Query(int x,int y,int d)
{
	int ret=0;
	for(int i=1;i<=Top;++i)
	{
		int k1=lower_bound(v[i].begin(),v[i].end(),mp(x+d,inf))-v[i].begin();
		int k2=lower_bound(v[i].begin(),v[i].end(),mp(x-d,000))-v[i].begin();
		ret+=Query(rt[i][k2],rt[i][k1],1,N,max(1,y-d),min(y+d,N));
	}
	return ret;
}
int n,Q,a[MAX];
int main()
{
	n=read();Q=read();
	for(int i=1;i<MAXNODE;++i)St[++top]=i,vis[i]=false;
	for(int i=1;i<=n;++i)a[i]=read(),insert(a[i]+i,a[i]-i+py);
	while(Q--)
	{
		scanf("%s",ch);int x=read(),y=read();
		if(ch[0]=='Q')printf("%d\n",Query(a[x]+x,a[x]-x+py,y));
		else a[x]=y,insert(a[x]+x,a[x]-x+py);
	}
	return 0;
}
【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.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 数列(二进制分组)
		这题其实可以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 ... 
随机推荐
- 统计学习方法c++实现之二 k近邻法
			统计学习方法c++实现之二 k近邻算法 前言 k近邻算法可以说概念上很简单,即:"给定一个训练数据集,对新的输入实例,在训练数据集中找到与这个实例最邻近的k个实例,这k个实例的多数属于某个类 ... 
- Python中的异常(Exception)处理
			异常 当你的程序出现例外情况时就会发生异常(Exception).例如,当你想要读取一个文件时,而那个文件却不存在,怎么办?又或者你在程序执行时不小心把它删除了,怎么办?这些通过使用异常来进行处理. ... 
- 前端开发利器 livereload -- 从此告别浏览器F5键
			各位从事前端开发的童鞋们,大家每天coding && coding,然后F5 && F5,今天推荐一个静态文件在浏览器中自动更新的扩展 livereload,不同手动刷 ... 
- python打印对象的所有可操作内容
			print('\n'.join(['%s:%s' % item for item in 对象.__dict__.items()])) 
- Netty源码分析第4章(pipeline)---->第6节: 传播异常事件
			Netty源码分析第四章: pipeline 第6节: 传播异常事件 讲完了inbound事件和outbound事件的传输流程, 这一小节剖析异常事件的传输流程 首先我们看一个最最简单的异常处理的场景 ... 
- shell--read命令
			read命令 -p(提示语句) -n(字符个数) -t(等待时间) -s(不回显) 1.基本读取read命令接收标准输入(键盘)的输入,或其他文件描述符的输入(后面在说).得到输入后,read命令将数 ... 
- Java调用XML的方法:DocumentBuilderFactory
			(1)首先得到:得到 DOM 解析器的工厂实例 DocumentBuilderFactory domfac=DocumentBuilderFactory.newInstance(); (2)然后从 D ... 
- [奇葩问题]  Error Domain=NSURLErrorDomain Code=-1003
			问题描述: 新上线的产品,ios同事拿着一串报错来找我,日志如下:err =Error Domain=NSURLErrorDomain Code=-1003 "未能找到使用指定主机名的服务器 ... 
- 1、数据库与excel表格的数据导入导出
			1.居民用户界面中,excel数据导入导出: 2.其他5张表数据显示到本角色主页的container容器中. 
- 《Spring2之站立会议7》
			<Spring2之站立会议7> 昨天,查相关资料解决debug:: 今天,解决了debug: 遇到问题,一些问题是得到解决了,但是一些还未被解决. 
