BZOJ_2989_数列&&BZOJ_4170_极光_KDTree

BZOJ_2989_数列&&BZOJ_4170_极光_KDTree

Description

"若是万一琪露诺(俗称rhl)进行攻击,什么都好,冷静地回答她的问题来吸引她。对方表现出兴趣的话,那就慢
慢地反问。在她考虑答案的时候,趁机逃吧。就算是很简单的问题,她一定也答不上来。"               
 --《上古之魔书》
天空中出现了许多的北极光,这些北极光组成了一个长度为n的正整数数列a[i],远古之魔书上记载到:2个位置的g
raze值为两者位置差与数值差的和:
graze(x,y)=|x-y|+|a[x]-a[y]|。
要想破解天罚,就必须支持2种操作(k都是正整数):
Modify x k:将第x个数的值修改为k。
Query x k:询问有几个i满足graze(x,i)<=k。
由于从前的天罚被圣王lmc破解了,所以rhl改进了她的法术,询问不仅要考虑当前数列,还要考虑任意历史版本,
即统计任意位置上出现过的任意数值与当前的a[x]的graze值<=k的对数。(某位置多次修改为同样的数值,按多次
统计)

Input

第1行两个整数n,q。分别表示数列长度和操作数。
第2行n个正整数,代表初始数列。
第3~q+2行每行一个操作。
N<=40000, 修改操作数<=60000, 询问操作数<=10000, Max{a[i]}(含修改)<=80000

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

看起来KDTree可做,只是查询的不是一个矩形。
那就旋转坐标系一下就变成矩形查询了。
不过好像暴力不旋转坐标系就可过的样子。
试了一下真A了。
 
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 200050
#define ls ch[p][0]
#define rs ch[p][1]
#define _min(x,y) ((x)<(y)?(x):(y))
#define _max(x,y) ((x)>(y)?(x):(y))
int ch[N][2],mx[N][2],mn[N][2],siz[N],now,root,val[N],n;
struct Point {
	int p[2];
	bool operator < (const Point &x) const {
		return p[now]==x.p[now]?p[!now]<x.p[!now]:p[now]<x.p[now];
	}
}a[N];
inline char nc() {
	static char buf[100000],*p1,*p2;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
char rc() {
	char s=nc();
	while(s!='Q'&&s!='M') s=nc();
	return s;
}
int rd() {
	int x=0; char s=nc();
	while(s<'0'||s>'9') s=nc();
	while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc();
	return x;
}
void pushup(int p,int x) {
	int i;
	for(i=0;i<2;i++) mn[p][i]=_min(mn[p][i],mn[x][i]),mx[p][i]=_max(mx[p][i],mx[x][i]);
	siz[p]+=siz[x];
}
int build(int l,int r,int type) {
	int mid=(l+r)>>1; now=type;
	nth_element(a+l,a+mid,a+r+1);
	int i;
	for(i=0;i<2;i++) mn[mid][i]=mx[mid][i]=a[mid].p[i];
	siz[mid]=1;
	ch[mid][0]=ch[mid][1]=0;
	if(l<mid) ch[mid][0]=build(l,mid-1,!type),pushup(mid,ch[mid][0]);
	if(r>mid) ch[mid][1]=build(mid+1,r,!type),pushup(mid,ch[mid][1]);
	return mid;
}
void insert(int x) {
	int p=root;
	now=0; 
	mx[x][0]=mn[x][0]=a[x].p[0];
	mx[x][1]=mn[x][1]=a[x].p[1];
	siz[x]=1;
	while(1) {
		pushup(p,x);
		if(a[x]<a[p]) {
			if(ls) p=ls;
			else {ls=x; return ;}
		}else {
			if(rs) p=rs;
			else {rs=x; return ;}
		}
		now=!now;
	}
}
int Abs(int x) {return x>0?x:-x;}
int dismin(int x,int y,int p) {
	return _max(mn[p][0]-x,0)+_max(x-mx[p][0],0)+_max(mn[p][1]-y,0)+_max(y-mx[p][1],0);
}
int dismax(int x,int y,int p) {
	return max(Abs(x-mx[p][0]),Abs(x-mn[p][0]))+max(Abs(y-mx[p][1]),Abs(y-mn[p][1]));
}
int query(int x,int y,int k,int p) {
	if(dismax(x,y,p)<=k) return siz[p];
	int re=0;
	if(Abs(a[p].p[0]-x)+Abs(a[p].p[1]-y)<=k) re++;
	if(ls&&dismin(x,y,ls)<=k) re+=query(x,y,k,ls);
	if(rs&&dismin(x,y,rs)<=k) re+=query(x,y,k,rs);
	return re;
}
int main() {
	n=rd(); int Q=rd();
	int i,x,y;
	for(i=1;i<=n;i++) {
		val[i]=rd();
		a[i]=(Point){i,val[i]};
	}
	root=build(1,n,0);
	while(Q--) {
		char opt=rc();
		x=rd(); y=rd();
		if(opt=='Q') {
			printf("%d\n",query(x,val[x],y,root));
		}else {
			val[x]=y;
			a[++n]=(Point){x,y};
			insert(n);
			if(n%10000==0) root=build(1,n,0);
		}
	}
}

 

 
posted @ 2018-07-08 08:10  fcwww  阅读(233)  评论(0编辑  收藏  举报