bzoj 2989&&4170: 数列

首先所谓的“可持久化” 就是加入一个新的元素
把<x,a[x]>看成平面上的一个点,graze函数就是曼哈顿距离
求点集中曼哈顿距离≤k的,自然要转换为切比雪夫距离的一个矩阵内点的个数
然后CDQ分治或者强上数据结构
注意矩阵y坐标取min要和1算,因为查询的时候是L-1,而树状数组不允许查询负数位置
   
   
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
 
#define ll long long
#define inf 1e9
#define eps 1e-10
#define md
#define N 200010
using namespace std;
struct QQ { int x,y,l,r; bool ty;} q[N],q1[N],q2[N];
int a[N],c[N],ans[N];
char st[100];
//N<=60000 修改操作数<=40000 询问<=50000 Max{a[i]}含修改<=100000
const int mxn=160001;
void add(int x,int d)
{
for (;x<mxn;x+=x&(-x)) c[x]+=d;
}
int cal(int x)
{
int ans=0;
for (;x;x-=x&(-x)) ans+=c[x];
return ans;
}
void solve(int l,int r,int ql,int qr)
{
if (l>r||ql>qr) return;
int mid=(ql+qr)>>1;
for (int i=l;i<=r;i++)
if (q[i].ty==0)
{
if (q[i].x<=mid) add(q[i].y,1);
}
else
{
if (q[i].x>=mid)
{
int a=q[i].y,b=1; if (a<0) a=-a,b=-1;
ans[a]+=(cal(q[i].r)-cal(q[i].l-1))*b;
}
}
for (int i=l;i<=r;i++)
if (q[i].ty==0&&q[i].x<=mid) add(q[i].y,-1);
int w1=0,w2=0,w=l-1;
for (int i=l;i<=r;i++)
if (q[i].x<mid) q1[++w1]=q[i];
else if (q[i].x>mid) q2[++w2]=q[i];
for (int i=1;i<=w1;i++) q[++w]=q1[i]; int pos=w;
for (int i=1;i<=w2;i++) q[++w]=q2[i];
solve(l,pos,ql,mid-1); solve(pos+1,w,mid+1,qr);
}
 
int main()
{
int n,Q,w=0,mn=inf,mx=-inf,qs=0; scanf("%d%d",&n,&Q);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
q[++w]=(QQ){i-a[i],i+a[i],0,0,0};
mn=min(mn,i-a[i]); mx=max(mx,i-a[i]);
}
for (int i=1;i<=Q;i++)
{
int s,t; scanf("%s%d%d",st,&s,&t);
if (st[0]=='Q')
{
int x=s-a[s],y=s+a[s];
qs++;
q[++w]=(QQ){x-t-1,-qs,max(y-t,1),min(y+t,mxn),1};
q[++w]=(QQ){x+t,qs,max(y-t,1),min(y+t,mxn),1};
}
else
{
a[s]=t; mn=min(mn,s-a[s]); mx=max(mx,s-a[s]);
q[++w]=(QQ){s-a[s],s+a[s],0,0,0};
}
}
solve(1,w,mn,mx);
for (int i=1;i<=qs;i++) printf("%d\n",ans[i]);
return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值