[BZOJ]4170: 极光 2989: 数列 CDQ分治+树状数组
2017-11-30 15:58
344 查看
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的对数。(某位置多次修改为同样的数值,按多次统计)
给定一个长度为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的对数。(某位置多次修改为同样的数值,按多次统计)
题解:
一开始看,分四种情况讨论的话是四维偏序,后来灵机一动,把它看做平面上的点的话,求的就是距离不超过k的有多少个点,这个区域恰好是一个菱形,那么把坐标系旋转一下,就可以变成询问一个矩形内数的和了,那么就和简单题的方法一样了。(不知道为什么数组要莫名开大)代码:
#include<bits/stdc++.h> using namespace std; #define LL long long const int Maxq=150010; int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return x*f; } int n,Q,a[600100],cnt,idcnt=0; int X(int x,int y){return x+y-1;} int Y(int x,int y){return n-x+y;} LL ans[500100]; struct Opt{int x,y,k,type,id;}q[Maxq],q1[Maxq<<2],temp[Maxq<<2]; int s[4000010]; void add(int x,int y){if(x<=0)return;for(;x<=4000000;x+=(x&-x))s[x]+=y;} LL getsum(int x){LL re=0;for(;x>0;x-=(x&-x))re+=(LL)(s[x]);return re;} int List[Maxq<<2]; void solve(int l,int r) { if(l==r)return; int mid=l+r>>1; solve(l,mid);solve(mid+1,r); int i=l,j=mid+1,len=0,o=0; while(i<=mid&&j<=r) { 10b4f if(q1[i].x<q1[j].x||(q1[i].x==q1[j].x&&q1[i].type<q1[j].type)) { if(q1[i].type==1)add(q1[i].y,1),List[++o]=q1[i].y; temp[++len]=q1[i++]; } else { if(q1[j].type==2)ans[q1[j].id]+=getsum(q1[j].y); else if(q1[j].type==3)ans[q1[j].id]-=getsum(q1[j].y); temp[++len]=q1[j++]; } } int t=i; while(i<=mid)temp[++len]=q1[i++]; while(j<=r) { if(q1[j].type==2)ans[q1[j].id]+=getsum(q1[j].y); else if(q1[j].type==3)ans[q1[j].id]-=getsum(q1[j].y); temp[++len]=q1[j++]; } for(int p=1;p<=o;p++)add(List[p],-1); for(int p=1;p<=len;p++)q1[l+p-1]=temp[p]; } int main() { n=read(),Q=read(); for(int i=1;i<=n;i++)q[i].type=1,q[i].x=i,q[i].y=a[i]=read(); for(int i=1;i<=Q;i++) { char op[8]; scanf("%s",op); int u1=read(),u2=read(),t=i+n; if(op[0]=='M')q[t].type=1,q[t].x=u1,q[t].y=u2,a[u1]=u2; else q[t].type=2,q[t].x=u1,q[t].y=a[u1],q[t].k=u2,q[t].id=++idcnt; } for(int i=1;i<=n;i++)q1[i]=q[i],q1[i].x=X(q[i].x,q[i].y),q1[i].y=Y(q[i].x,q[i].y);cnt=n; for(int i=1+n;i<=Q+n;i++) { if(q[i].type==1)q1[++cnt]=q[i],q1[cnt].x=X(q[i].x,q[i].y),q1[cnt].y=Y(q[i].x,q[i].y); else { int X1=q[i].x,Y1=q[i].y-q[i].k,X2=q[i].x,Y2=q[i].y+q[i].k; int x1=X(X1,Y1),y1=Y(X1,Y1),x2=X(X2,Y2),y2=Y(X2,Y2); q1[++cnt].type=2;q1[cnt].x=x2;q1[cnt].y=y2; q1[++cnt].type=2;q1[cnt].x=x1-1;q1[cnt].y=y1-1; q1[++cnt].type=3;q1[cnt].x=x1-1;q1[cnt].y=y2; q1[++cnt].type=3;q1[cnt].x=x2;q1[cnt].y=y1-1; q1[cnt].id=q1[cnt-1].id=q1[cnt-2].id=q1[cnt-3].id=q[i].id; } } solve(1,cnt); for(int i=1;i<=idcnt;i++)printf("%lld\n",ans[i]); }
相关文章推荐
- BZOJ_2989_数列&&BZOJ_4170_极光_KDTree
- bzoj 2989: 数列&4170: 极光
- BZOJ2989 数列/BZOJ4170 极光
- 【BZOJ 4170】 4170: 极光 (CDQ分治)
- [bzoj2989]数列_KD-Tree_旋转坐标系
- 【BZOJ2989】数列 kd-tree
- bzoj2989: 数列&&4170: 极光
- 【bzoj2989】数列 KD-tree+旋转坐标系
- bzoj 2989&&4170: 数列
- 【bzoj2989】【数列】【cdq分治+树状数组】
- BZOJ 2989 数列
- BZOJ4170 极光(CDQ分治 或 树套树)
- BZOJ4170 极光(CDQ分治 或 树套树)
- BZOJ 2989 数列 变换坐标系 主席树
- BZOJ2989 数列(二进制分组)
- 【线段树】BZOJ2989 数列
- BZOJ 2989: 数列/4170: 极光
- 【BZOJ2431】【HAOI2009】逆序对数列 DP
- [Splay] BZOJ1500: [NOI2005]维修数列
- BZOJ 1500 [NOI2005]维修数列