zoukankan      html  css  js  c++  java
  • [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) o (x+y , x-y))
    切比雪夫距离转曼哈顿距离 : ((x , y) o (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
    ",query(Tx - y , Ty - y , Tx + y , Ty + y , rtp)) ;
            }
        }
        return 0 ;
    }
    
  • 相关阅读:
    关于Python中的yield
    Python的getattr(),setattr(),delattr(),hasattr()
    django Forgienkey字段 在前台用js做处理
    利用checkbox的到值,并且存到数据库修改的话要显示之前选择的
    关于django批量上传图片
    block extends include三者的差别跟用法
    全智能建造
    共享经济
    新工匠
    运营方案
  • 原文地址:https://www.cnblogs.com/beretty/p/10639151.html
Copyright © 2011-2022 走看看