您的位置:首页 > 其它

BZOJ_2989_数列&&BZOJ_4170_极光_KDTree

2018-07-08 08:10 585 查看

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

[0] #define rs ch[p][1] #define _min(x,y) ((x)<(y)?(x):(y)) #define _max(x,y) ((x)>(y)?(x):(y)) int ch [2],mx [2],mn [2],siz ,now,root,val ,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 ; 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); } } }

[p] 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: