• 【BZOJ2989】数列(CDQ分治,扫描线)


    【BZOJ2989】数列(CDQ分治)

    题面

    BZOJ
    权、。、。、权限题。。

    题解

    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 询问<=50000 Max{a[i]}含修改<=100000

    题解

    很容易想到把数列上的每一个点看成平面上的一个点,
    那么题目中给定的限制变成了求距离一个点的曼哈顿距离在一个范围内的点。
    很明显,这个区域在平面上是一个菱形,旋转(45°)之后就成为了一个正方形。
    对于一个点((x,y)),旋转(45°)的方法是变成((x+y,x-y))
    那么询问曼哈顿距离不超过(k)就变成了询问矩形(([x+y-k,x+y+k],[x-y-k,x-y+k]))内的点数。
    那么,问题变成了,加入一个点,查询一个矩形内的点数,
    直接(CDQ)分治,然后扫描线统计答案就好了。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define MAX 500100
    #define py 250050
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int c[MAX];
    int lb(int x){return x&(-x);}
    void modify(int x,int w){while(x<MAX)c[x]+=w,x+=lb(x);}
    int getsum(int x){int ret=0;while(x)ret+=c[x],x-=lb(x);return ret;}
    int getsum(int l,int r){return getsum(r)-getsum(l-1);}
    int n,Q,a[MAX],ans[MAX];
    char ch[10];
    struct Opt{int opt,x,y,d,id;}p[MAX],tmp[MAX];
    bool operator<(Opt a,Opt b){if(a.x!=b.x)return a.x<b.x;return a.opt>b.opt;}
    int tot,cnt;
    void CDQ(int l,int r)
    {
    	if(l==r)return;int mid=(l+r)>>1,t=0;
    	for(int i=l;i<=mid;++i)if(!p[i].opt)tmp[++t]=p[i];
    	for(int i=mid+1;i<=r;++i)
    	{
    		if(!p[i].opt)continue;
    		tmp[++t]=(Opt){+1,p[i].x-p[i].d,p[i].y,p[i].d,p[i].id};
    		tmp[++t]=(Opt){-1,p[i].x+p[i].d,p[i].y,p[i].d,p[i].id};
    	}
    	sort(&tmp[1],&tmp[t+1]);
    	for(int i=1;i<=t;++i)
    		if(tmp[i].opt==0)modify(tmp[i].y,1);
    		else ans[tmp[i].id]-=tmp[i].opt*getsum(tmp[i].y-tmp[i].d,tmp[i].y+tmp[i].d);
    	for(int i=1;i<=t;++i)if(tmp[i].opt==0)modify(tmp[i].y,-1);
    	CDQ(l,mid);CDQ(mid+1,r);
    }
    int main()
    {
    	n=read();Q=read();
    	for(int i=1;i<=n;++i)a[i]=read(),p[++tot]=(Opt){0,i+a[i]+py,i-a[i]+py,0,0};
    	for(int i=1;i<=Q;++i)
    	{
    		scanf("%s",ch);
    		if(ch[0]=='Q')
    		{
    			int x=read();
    			p[++tot]=(Opt){1,x+a[x]+py,x-a[x]+py,read(),++cnt};
    		}
    		else
    		{
    			int x=read();a[x]=read();
    			p[++tot]=(Opt){0,x+a[x]+py,x-a[x]+py,0,0};
    		}
    	}
    	CDQ(1,tot);
    	for(int i=1;i<=cnt;++i)printf("%d
    ",ans[i]);
    	return 0;
    }
    
    
  • 相关阅读:
    体验cygwin纪实
    播布客视频PIT专用播放器MBOO2015
    rpm基本命令参考
    rhel7.x配置本地yum
    mtr网络连通性测试
    Oracle下载汇聚
    Spring Cloud心跳监测
    Hystrix的用法
    Redis系列十:缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级
    dubbo异步调用三种方式
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9464360.html
Copyright © 2020-2023  润新知