[BZOJ4170]极光

Description

天空中出现了许多的北极光,这些北极光组成了一个长度为n的正整数数列a[i],远古之魔书上记载到:
2个位置的graze值为两者位置差与数值差的和:
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


题解

曼哈顿距离转切比雪夫距离
首先可以发现把\((i,val_i)\)映射到坐标系上的话题目要求的就是找到与这个点的曼哈顿距离\(\le k\)的点的个数
但是曼哈顿距离不好处理
我们可以将其转化成切比雪夫距离来处理
简单介绍一下:

曼哈顿距离:对于点\((x_1,y_1),(x_2,y_2)\),曼哈顿距离\(=|x1-x2|+|y1-y2|\)
切比雪夫距离:对于点\((x_1,y_1),(x_2,y_2)\),切比雪夫距离\(=max(|x1-x2|,|y1-y2|)\)

然后曼哈顿距离和切比雪夫距离是可以互相转化的:

曼哈顿距离转切比雪夫距离:\((x,y) \to (x+y , x-y)\)
切比雪夫距离转曼哈顿距离 : \((x , y) \to (\frac{x+y}{2} , \frac{x-y}{2})\)
总体的感觉就是切比雪夫距离就是把曼哈顿距离转一下再放大一下

那么对于这道题
就把\((i,val_i)\)转成\((i+val_i,i-val_i)\)
然后查询的时候就直接查切比雪夫距离与点\((i+val_i,i-val_i)\le k\)的点的个数即可
可以用\(KDTree\)解决

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int M = 100005 ;
using namespace std ;
 
inline int read() {
    char c = getchar() ; int x = 0 , w = 1 ;
    while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
    while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
    return x*w ;
}
 
int n , Num , val[M] ;
int tot , rtp , K ;
struct Poi {
    int x[2] ;
} p[M] ; 
struct Node {
    Poi tp ;
    int lsn , rsn , sz , tmi[2] , tmx[2] ;
} t[M] ;
inline bool operator < (Poi a , Poi b) {
    return a.x[K] < b.x[K] ;
}
# define ls t[now].lsn
# define rs t[now].rsn
inline void pushup(int now) {
    for(int k = 0 ; k <= 1 ; k ++) {
        t[now].tmi[k] = t[now].tmx[k] = t[now].tp.x[k] ;
        if(ls) {
            t[now].tmi[k] = min(t[now].tmi[k] , t[ls].tmi[k]) ;
            t[now].tmx[k] = max(t[now].tmx[k] , t[ls].tmx[k]) ;
        }
        if(rs) {
            t[now].tmi[k] = min(t[now].tmi[k] , t[rs].tmi[k]) ;
            t[now].tmx[k] = max(t[now].tmx[k] , t[rs].tmx[k]) ;
        }
    }
    t[now].sz = t[ls].sz + t[rs].sz + 1 ;
}
int build(int l , int r , int W) {
    if(l > r) return 0 ; K = W ;
    int cnt = ++ tot , mid = (l + r) >> 1 ;
    nth_element(p + l , p + mid , p + r + 1) ;
    t[cnt].tp = p[mid] ; 
    t[cnt].lsn = build(l , mid - 1 , (W ^ 1)) ;
    t[cnt].rsn = build(mid + 1 , r , (W ^ 1)) ;
    pushup(cnt) ; return cnt ;
}
void Insert(Poi po , int &now , int W) {
    if(!now) {
        now = ++ tot ; t[now].tp = po ;
        pushup(now) ; return ;
    }
    if(po.x[W] <= t[now].tp.x[W]) Insert(po , ls , (W ^ 1)) ;
    else Insert(po , rs , (W ^ 1)) ;
    pushup(now) ;
}
inline bool Allin(int ax , int ay , int bx , int by , int Ax , int Ay , int Bx , int By) {
    return (Ax >= ax && Ay >= ay && Bx <= bx && By <= by) ;
}
inline bool Allout(int ax , int ay , int bx , int by , int Ax , int Ay , int Bx , int By) {
    return (Ax > bx || Ay > by || Bx < ax || By < ay) ;
}
int query(int lx , int ly , int rx , int ry , int now) {
    if(!now) return 0 ; int ret = 0 ;
    if(Allin(lx , ly , rx , ry , t[now].tmi[0] , t[now].tmi[1] , t[now].tmx[0] , t[now].tmx[1])) return t[now].sz ;
    if(Allout(lx , ly , rx , ry , t[now].tmi[0] , t[now].tmi[1] , t[now].tmx[0] , t[now].tmx[1])) return 0 ;
    if(Allin(lx , ly , rx , ry , t[now].tp.x[0] , t[now].tp.x[1] , t[now].tp.x[0] , t[now].tp.x[1]) ) ++ ret ;
    ret += query(lx , ly , rx , ry , ls) + query(lx , ly , rx , ry , rs) ;  
    return ret ;
}
# undef ls
# undef rs
int main() {
    n = read() ; int Case = read() ;
    for(int i = 1 ; i <= n ; i ++) val[i] = read() ;
    for(int i = 1 ; i <= n ; i ++) {
        p[i].x[0] = i + val[i] , 
        p[i].x[1] = i - val[i] ;
    }
    Num = n ;
    rtp = build(1 , Num , 0) ;
    char opt[10] ; int x , y , Tx , Ty ;
    while(Case --) {
        scanf("%s",opt) ; 
        x = read() ; y = read() ;
        if(opt[0] == 'M') {
            val[x] = y ;
            p[++Num].x[0] = x + y ;
            p[Num].x[1] = x - y ;
            Insert(p[Num] , rtp , 0) ;
            if(Num % 10001 == 0) {
                tot = 0 ;
                rtp = build(1 , Num , 0) ;
            }
        }
        else {
            Tx = x + val[x] , Ty = x - val[x] ;
            printf("%d\n",query(Tx - y , Ty - y , Tx + y , Ty + y , rtp)) ;
        }
    }
    return 0 ;
}
posted @ 2019-04-01 21:35  beretty  阅读(183)  评论(0编辑  收藏  举报