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
2 4 3
Query 2 2
Modify 1 3
Query 2 2
Modify 1 2
Query 1 1
Sample Output
2
3
3
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);
}
}
}