[bzoj2002]弹飞绵羊
来源:互联网 发布:unity3d 多个摄像机 编辑:程序博客网 时间:2024/04/28 08:55
题目大意
有N个点,每个点有一个系数a[i],你处于位置i可以走到i+a[i],若i+a[i]>n则你走出了地图。现M个操作有两种:1、把a[j]修改为k。2、询问你位于点j时,需要走多少部走出地图。n<=2*10^5,m<=10^5。
LCT裸题
我们可以转化为如下问题:1、将x的父亲设为y。2、询问x的深度。
那就变成了LCT裸题,为了支持询问操作只需要维护size即可。
#include<cstdio>#include<algorithm>#include<stack>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=200000+10;stack<int> sta;int father[maxn],size[maxn],pp[maxn],tree[maxn][2],a[maxn];bool bz[maxn];int i,j,k,l,t,n,m;void update(int x){ size[x]=size[tree[x][0]]+size[tree[x][1]]+1;}int pd(int x){ return tree[father[x]][1]==x;}void rotate(int x){ int y=father[x],z=pd(x); tree[y][z]=tree[x][1-z]; if (tree[x][1-z]) father[tree[x][1-z]]=y; father[x]=father[y]; if (father[y]) tree[father[y]][pd(y)]=x; tree[x][1-z]=y; father[y]=x; update(y); update(x); if (pp[y]) pp[x]=pp[y],pp[y]=0;}void clear(int x){ if (bz[x]){ bz[x]=0; if (tree[x][0]) bz[tree[x][0]]^=1; if (tree[x][1]) bz[tree[x][1]]^=1; swap(tree[x][0],tree[x][1]); }}void remove(int x,int y){ while (x!=y){ sta.push(x); x=father[x]; } while (!sta.empty()){ clear(sta.top()); sta.pop(); }}void splay(int x,int y){ remove(x,y); while (father[x]!=y){ if (father[father[x]]!=y) if (pd(x)==pd(father[x])) rotate(father[x]);else rotate(x); rotate(x); }}void access(int x){ int y; splay(x,0); father[tree[x][1]]=0; if (tree[x][1]) pp[tree[x][1]]=x; tree[x][1]=0; update(x); while (pp[x]){ y=pp[x]; splay(y,0); father[tree[y][1]]=0; if (tree[y][1]) pp[tree[y][1]]=y; tree[y][1]=x; father[x]=y; pp[x]=0; update(y); splay(x,0); }}void makeroot(int x){ access(x); splay(x,0); bz[x]^=1;}void cut(int x,int y){ access(x); splay(y,0); pp[y]=0;}void link(int x,int y){ makeroot(x); splay(y,0); pp[y]=x; makeroot(n+1);}int main(){ scanf("%d",&n); fo(i,1,n){ scanf("%d",&a[i]); j=(i+a[i]>n)?n+1:i+a[i]; link(j,i); } scanf("%d",&m); while (m--){ scanf("%d%d",&t,&j); j++; if (t==1){ access(j); splay(j,0); printf("%d\n",size[tree[j][0]]); } else{ scanf("%d",&k); l=(j+a[j]>n)?n+1:j+a[j]; cut(l,j); a[j]=k; l=(j+a[j]>n)?n+1:j+a[j]; link(l,j); } }}
不过我们有更好的方法。
分块大法好
我们分块后,对每一个元素维护两个东西:b[i]表示i一直跳跳出自己所在块后跳到了哪个点,d[i]表示i跳出自己所在块的所需步数。有了这两个数组就可以进行询问,而修改操作暴力重建整个块就好了。
#include<cstdio>#include<algorithm>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;const int maxn=200000+10;int a[maxn],b[maxn],d[maxn];int i,j,k,l,t,n,m,ans,c;int main(){ scanf("%d",&n); c=floor(sqrt(n))+1; fo(i,1,n) scanf("%d",&a[i]); fd(i,n,1){ k=min(((i-1)/c+1)*c,n); if (i+a[i]>k) d[i]=1,b[i]=i+a[i]; else d[i]=d[i+a[i]]+1,b[i]=b[i+a[i]]; } scanf("%d",&m); while (m--){ scanf("%d",&t); if (t==1){ scanf("%d",&j); j++; ans=0; while (j<=n){ ans+=d[j]; j=b[j]; } printf("%d\n",ans); } else{ scanf("%d%d",&j,&k); j++; a[j]=k; k=min(((j-1)/c+1)*c,n); fd(i,k,(j-1)/c*c+1){ if (i+a[i]>k) d[i]=1,b[i]=i+a[i]; else d[i]=d[i+a[i]]+1,b[i]=b[i+a[i]]; } } }}
1 0
- BZOJ2002弹飞绵羊
- 【bzoj2002】弹飞绵羊
- bzoj2002 弹飞绵羊
- 【BZOJ2002】弹飞绵羊
- bzoj2002 弹飞绵羊
- [bzoj2002]弹飞绵羊
- BZOJ2002弹飞绵羊
- bzoj2002弹飞绵羊
- 【BZOJ2002】弹飞绵羊
- 【bzoj2002】弹飞绵羊
- BZOJ2002弹飞绵羊
- BZOJ2002弹飞绵羊
- BZOJ2002-弹飞绵羊 LCT
- 【bzoj2002】【LCT】弹飞绵羊
- bzoj2002 弹飞绵羊2
- 【bzoj2002】弹飞绵羊 LCT
- [HNOI2010][BZOJ2002]弹飞绵羊
- [bzoj2002][LCT]弹飞绵羊
- C#获取日期
- <LeetCode OJ> 206. Reverse Linked List
- Netty in Action 读书
- 挂题解咯~
- c/c艹和汇编混合编程
- [bzoj2002]弹飞绵羊
- unix 网络编程 卷一(unp.h)
- oracle正则表达式
- js屏蔽浏览器右键菜单
- Hadoop Yarn集群 主节点的 data node没有启动成功
- Android 四大组件之ContentProvider
- [iOS]将含有NSData数据的数组转化为json字符串报错:reason: 'Invalid type in JSON write (NSConcreteMutableData)
- LeetCode Odd Even Linked List
- nginx 中location和root,你确定真的明白他们关系?