• 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
    ",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);
    		}
    	}
    }
    
     
  • 相关阅读:
    kvm介绍
    正式班D24
    正式班D23
    正式班D21
    正式班D20
    正式班D19
    正式班D18
    正式班D17
    正式班D16
    正式班D15
  • 原文地址:https://www.cnblogs.com/suika/p/9279123.html
Copyright © 2020-2023  润新知