【BZOJ2989】—数列(CDQ分治+曼哈顿距离转切比雪夫距离)
大意:定义2个位置的值为两者位置差与数值差的和,即
支持单点修改数值,询问所有出现过的数值与一个指定位置数的的个数
如果我们把位置看做,数值看做;
那问题就变成了询问有多少个点距当前点的曼哈顿距离
也就是对于一个斜着的正方形数点
我们考虑把曼哈顿距离转变成切比雪夫距离,就变成了一个二维数点问题了
直接上分治
也可以直接用暴力二位树状数组做,时空都是
但不知道为什么总是有2个点
代码
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return res*f;
}
const int N=1000005;
const int ext=100000;
int n,q,cnt,tot,a[N],ans[N];
struct ask{
int l,r,op,pos;
}p[N];
int tr[N];
inline bool comp(const ask &a,const ask &b){
if(a.l==b.l)return a.r<b.r;
return a.l<b.l;
}
inline int lowbit(int x){
return (x&(-x));
}
inline void update(int pos,int k){
for(;pos<N;pos+=lowbit(pos))tr[pos]+=k;
}
inline int query(int pos,int res=0){
for(;pos;pos-=lowbit(pos))res+=tr[pos];return res;
}
char op[10];
#define mid ((l+r)>>1)
inline void cdq(int l,int r){
if(l==r)return;
cdq(l,mid),cdq(mid+1,r);
sort(p+l,p+mid+1,comp);
sort(p+mid+1,p+r+1,comp);
int i=l;
for(int j=mid+1;j<=r;j++){
for(;i<=mid&&p[i].l<=p[j].l;i++)
if(p[i].op==1)update(p[i].r,1);
if(p[j].op==2)ans[p[j].pos]+=query(p[j].r);
}
for(int j=l;j<i;j++)if(p[j].op==1)update(p[j].r,-1);
}
int main(){
n=read(),q=read();
for(int i=1;i<=n;i++){
a[i]=read();
int x=a[i]+i,y=i-a[i]+ext;
p[++tot].l=x,p[tot].r=y,p[tot].op=1;
}
for(int i=1;i<=q;i++){
scanf("%s",op);
int x=read(),k=read();
switch (op[0]){
case 'Q':{
int x1=a[x]+x,y1=x-a[x]+ext;
int x2=x1+k,y2=y1+k;x1-=k,y1-=k;
x1=max(x1,1),y1=max(y1,1);
p[++tot].l=x1-1,p[tot].r=y1-1,p[tot].pos=++cnt,p[tot].op=2;
p[++tot].l=x2 ,p[tot].r=y1-1,p[tot].pos=++cnt,p[tot].op=2;
p[++tot].l=x1-1,p[tot].r=y2 ,p[tot].pos=++cnt,p[tot].op=2;
p[++tot].l=x2 ,p[tot].r=y2 ,p[tot].pos=++cnt,p[tot].op=2;
break;
}
case 'M':{
a[x]=k,
p[++tot].l=a[x]+x,p[tot].r=x-a[x]+ext,p[tot].op=1;
break;
}
}
}
cdq(1,tot);
for(int i=1;i<=cnt;i+=4){
cout<<(ans[i]-ans[i+1]-ans[i+2]+ans[i+3])<<'\n';
}
}
暴力(求看看为什么)
#include<bits/stdc++.h>
#include<tr1/unordered_map>
using namespace std;
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return res*f;
}
const int N=500005;
const int ext=100001;
using namespace tr1;
unordered_map<int,int>tr[N];
int n,q,a[N];
inline int lowbit(int x){
return (x&(-x));
}
inline void update(int x,int y){
for(int i=x;i<N;i+=lowbit(i))
for(int j=y;j<N;j+=lowbit(j)){
if(!tr[i][j])tr[i][j]=1;
else tr[i][j]=tr[i][j]+1;
//cout<<x<<" "<<y<<'\n';
}
}
inline int find(int x,int y){
int res=0;
for(int i=x;i;i-=lowbit(i))
for(int j=y;j;j-=lowbit(j))
res+=tr[i][j];
return res;
}
inline int query(int x1,int y1,int x2,int y2){
int res=0;x1=max(x1,1),y1=max(y1,1);
res=find(x1-1,y1-1);//cout<<res<<'\n';
res+=find(x2,y2);//,cout<<res<<'\n',
res-=find(x2,y1-1);//,cout<<res<<'\n';
res-=find(x1-1,y2);
return res;
}
char op[10];
int main(){
//freopen(";x.cpp","r",stdin);
n=read(),q=read();
for(int i=1;i<=n;i++){
a[i]=read();
update(i+a[i],i-a[i]+ext);
}
for(int i=1;i<=q;i++){
scanf("%s",op);
int x=read(),k=read();
switch(op[0]){
case 'Q':{
int x1=a[x]+x,y1=x-a[x]+ext;
cout<<query(x1-k,y1-k,x1+k,y1+k)<<'\n';//cout<<"TRUN"<<'\n';
break;
}
case 'M':{
a[x]=k,update(x+a[x],x-a[x]+ext);
break;
}
}
}
}