【BZOJ2989】—数列(CDQ分治+曼哈顿距离转切比雪夫距离)

传送门

大意:定义2个位置的grazegraze值为两者位置差与数值差的和,即graze(x,y)=xy+a[x]a[y]graze(x,y)=|x-y|+|a[x]-a[y]|
支持单点修改数值,询问所有出现过的数值与一个指定位置数的graze<=kgraze<=k的个数


如果我们把位置看做xx,数值看做yy;
那问题就变成了询问有多少个点距当前点的曼哈顿距离<=k<=k
也就是对于一个斜着的正方形数点

我们考虑把曼哈顿距离转变成切比雪夫距离,就变成了一个二维数点问题了

直接上CDQCDQ分治

也可以直接用mapmap暴力二位树状数组做,时空都是O(nlog2n)(unordered_map)O(nlog^2n)(unordered\_map)
但不知道为什么总是有2个点RERE

代码

CDQCDQ

#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])<<'
';
	}
}

暴力mapmap(求dalaodalao看看为什么RERE)

#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<<'
';
		}
}
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<<'
';
	res+=find(x2,y2);//,cout<<res<<'
',
	res-=find(x2,y1-1);//,cout<<res<<'
';
	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)<<'
';//cout<<"TRUN"<<'
';
				break;
			}
			case 'M':{
				a[x]=k,update(x+a[x],x-a[x]+ext);
				break;
			}
		}
	}
}
原文地址:https://www.cnblogs.com/stargazer-cyk/p/10366314.html