【线段树】BZOJ2989 数列
2018-02-23 21:40
357 查看
题意:
给定一个长度为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<=60000 修改操作数<=40000 询问<=50000 Max{a[i]}含修改<=100000
分析:
首先,观察它给出的graze值的计算方式:很容易发现,如果将每个值放在一个平面上,这个graze值所表示的就是两点间的曼哈顿距离。这样一来,这道题就比较显而易见了:我们将每个值看做一个平面上的点,其横坐标为x,纵坐标为a[x],每次修改值可以看做是在图上新加入一个点,每次询问,就可以看做是:在平面内求与某点的曼哈顿距离小于K的点的总数。
再进一步会发现,我们所求的范围,组成了一个正方形,我们只需要旋转一下坐标系,把原坐标系改为(x+y,-x+y),就成了一道很典型的二维线段树的题目。
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #define SF scanf #define PF printf #define MAXN 200010 using namespace std; const int lim=160000,liml=-60000,limr=100000; int rt[MAXN*4]; struct node{ int val,pl,pr; }tr[MAXN*100]; int cnt=0; void add(int l,int r,int& id,int py){ if(id==0) id=++cnt; tr[id].val++; if(l==r) return ; int mid=(l+r)>>1; if(mid>=py) add(l,mid,tr[id].pl,py); else add(mid+1,r,tr[id].pr,py); } void addx(int l,int r,int id,int px,int py){ add(liml,limr,rt[id],py); if(l==r) return ; int mid=(l+r)>>1; if(mid>=px) addx(l,mid,id*2,px,py); else addx(mid+1,r,id*2+1,px,py); } int que(int l,int r,int id,int l1,int r1){ if(id==0) return 0; if(l>=l1&&r<=r1) return tr[id].val; int mid=(l+r)>>1,res=0; if(mid>=l1) res+=que(l,mid,tr[id].pl,l1,r1); if(mid<r1) res+=que(mid+1,r,tr[id].pr,l1,r1); return res; } int quex(int l,int r,int id,int l1,int r1,int l2,int r2){ if(l>=l1&&r<=r1) return que(liml,limr,rt[id],l2,r2); int mid=(l+r)>>1,res=0; if(mid>=l1) res+=quex(l,mid,id*2,l1,r1,l2,r2); if(mid<r1) res+=quex(mid+1,r,id*2+1,l1,r1,l2,r2); return res; } char s[20]; int n,m,a[MAXN],x,y; int main(){ SF("%d%d",&n,&m); for(int i=1;i<=n;i++){ SF("%d",&a[i]); addx(1,lim,1,i+a[i],-i+a[i]); } for(int i=1;i<=m;i++){ SF("%s%d%d",s,&x,&y); if(s[0]=='Q'){ PF("%d\n",quex(1,lim,1,x+a[x]-y,x+a[x]+y,-x+a[x]-y,-x+a[x]+y)); } else{ a[x]=y; addx(1,lim,1,x+a[x],-x+a[x]); } } }
相关文章推荐
- BZOJ2989 数列/BZOJ4170 极光
- bzoj 2989: 数列&4170: 极光
- BZOJ 2989 数列
- [bzoj2989]数列_KD-Tree_旋转坐标系
- 【bzoj4636】【蒟蒻的数列】【线段树】
- BZOJ 2989 数列 变换坐标系 主席树
- bzoj1789 AHOI 维护数列(线段树)
- BZOJ_2989_数列&&BZOJ_4170_极光_KDTree
- [BZOJ]4170: 极光 2989: 数列 CDQ分治+树状数组
- BZOJ 4636: 蒟蒻的数列 线段树/扫描线 set
- 【bzoj2989】【数列】【cdq分治+树状数组】
- 【BZOJ-4636】蒟蒻的数列 动态开点线段树 ||(离散化) + 标记永久化
- BZOJ 4636: 蒟蒻的数列 分快,int64线段树
- BZOJ2989 数列(二进制分组)
- 【bzoj 4636】蒟蒻的数列(动态开点线段树)
- [bzoj4636]蒟蒻的数列_线段树
- 【BZOJ2989】数列 kd-tree
- bzoj4636 蒟蒻的数列(离散化+线段树)
- 【bzoj4636】蒟蒻的数列 离散化+线段树
- 【bzoj2989】数列 KD-tree+旋转坐标系