• bzoj2989&4170: 数列


    Description

    给定一个长度为n的正整数数列a[i]。
    定义2个位置的graze值为两者位置差与数值差的和,即graze(x,y)=|x-y|+|a[x]-a[y]|。
    2种操作(k都是正整数):
    1.Modify x k:将第x个数的值修改为k。
    2.Query x k:询问有几个i满足graze(x,i)<=k。因为可持久化数据结构的流行,询问不仅要考虑当前数列,还要考虑任意历史版本,即统计任意位置上出现过的任意数值当前的a[x]的graze值<=k的对数。(某位置多次修改为同样的数值,按多次统计)

    Input

    第1行两个整数n,q。分别表示数列长度和操作数。
    第2行n个正整数,代表初始数列。
    第3--q+2行每行一个操作。

    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

    HINT

    N<=60000 修改操作数<=40000 询问<=10000 Max{a[i]}含修改<=100000

    思路:考场上打了个暴力,竟然有70分....

    CDQ分治,先把坐标(x,y)转换成(x-y,x+y),然后就是正放着的矩形了,询问就是矩形中点的个数。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=60010,maxm=260010,maxq=500010;
    int n,q,a[maxn],ans[maxq],cnt,lim;
    bool que[maxq];char op[10];
    struct node{int num,id,op,x,y,t;}li[maxq],tmp[maxq];
    struct Bit{
        int val[maxq]; 
        void change(int x,int v){for (;x<=lim;x+=x&-x) val[x]+=v;}
        int query(int x){int res=0;for (;x;x-=x&-x) res+=val[x];return res;}
    }T;
     
    void add(int op,int id,int x,int y,int k){
        int xx=x-y,yy=x+y;
        if (!op) lim=max(lim,xx),lim=max(lim,yy),li[++cnt]=(node){cnt,id,op,xx,yy,0};
        else{
            int x1=xx-k,y1=yy-k,x2=xx+k,y2=yy+k;
            if (y1>0) li[++cnt]=(node){cnt,id,op,x1-1,y1-1,1};
            li[++cnt]=(node){cnt,id,op,x1-1,y2,-1};
            if (y1>0) li[++cnt]=(node){cnt,id,op,x2,y1-1,-1};
            li[++cnt]=(node){cnt,id,op,x2,y2,1};
            lim=max(lim,x2),lim=max(lim,y2);
        }
    }
     
    void solve(int l,int r){
        if (l==r) return;
        int mid=(l+r)>>1;
        solve(l,mid),solve(mid+1,r);
        for (int i=l,a=l,b=mid+1;i<=r;i++){
            node p;
            if (a<=mid&&(b>r||li[a].x<=li[b].x)) p=li[a++];
            else p=li[b++];
            if (p.num<=mid&&!p.op) T.change(p.y,1);
            if (p.num>mid&&p.op) ans[p.id]+=T.query(p.y)*p.t;
            tmp[i]=p;
        }
        for (int i=l;i<=r;i++) li[i]=tmp[i];
        for (int i=l;i<=r;i++) if (li[i].num<=mid&&!li[i].op) T.change(li[i].y,-1);
    }
     
    int main(){
        scanf("%d%d",&n,&q);
        for (int i=1;i<=n;i++) scanf("%d",&a[i]),add(0,i,i,a[i],0);
        for (int i=n+1,x,k;i<=n+q;i++){
            scanf("%s%d%d",op,&x,&k);
            if (op[0]=='M') a[x]=k,add(0,i,x,a[x],0);
            else que[i]=1,add(1,i,x,a[x],k);
        }
        n+=q,lim++,solve(1,cnt);
        for (int i=1;i<=cnt;i++) if (que[i]) printf("%d
    ",ans[i]);
        return 0;
    }


  • 相关阅读:
    堆和栈的区别!
    产品经理和程序员的爱恨情仇
    字符串MD5加密运算
    事件驱动模型。。。。有时间弄
    Apache服务器httpd.exe进程占用cpu超过50%的解决方法
    ZigBee Xbee S2通讯设置
    pipe-filter 真难找啊
    javacomm64位用不了,可以使用RXTXcomm for x64
    导入 sun.net.TelnetInputStream; 报错
    linux下gedit读取txt乱码解决办法
  • 原文地址:https://www.cnblogs.com/thythy/p/5493585.html
Copyright © 2020-2023  润新知