2002: [Hnoi2010]Bounce 弹飞绵羊
来源:互联网 发布:淘宝店铺怎么搞双11 编辑:程序博客网 时间:2024/05/16 11:11
题目链接
题目大意:维护数列,a[x]表示从x出发会到达x+a[x],支持两种操作
1.单点修改 2.查询从x出发经过几次会弹飞(坐标超过n)
题解:两种解法,LCT|分块
分块:
就可以YY出分块方法了
具体见代码
强啊
LCT:加一个根为n+1,x+a[x]为x的父亲,弹飞的点父亲为根,修改需要断边+连新边,查询则是把n+1转到根,再把x到根的路径提取,由于辅助树中splay按照深度关键字排序,根的左子树大小就是要被弹的次数
虽然分块复杂度高,但是跑的比LCT快……应该是我写的太挫了……
我的收获:可以多维护几个信息……常用的建树思想……
分块
#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>using namespace std;const int M=200005;int n,m,blo,num;int a[M],stp[M],nxt[M],pos[M];int query(int x){ int ret=0; while(nxt[x]) ret+=stp[x],x=nxt[x]; return ret;}void updata(int x,int v){ a[x]=v;int l=(pos[x]-1)*blo+1; for(int i=x;i>=l;i--)//类似初始化 if(pos[i]==pos[i+a[i]]) stp[i]=stp[i+a[i]]+1,nxt[i]=nxt[i+a[i]]; else stp[i]=1,nxt[i]=i+a[i]; }void work(){ int opt,x,y; while(m--){ scanf("%d%d",&opt,&x);x++; if(opt==1) printf("%d\n",query(x)); if(opt==2) scanf("%d",&y),updata(x,y); }}void init(){ cin>>n;blo=sqrt(n);num=(n-1)/blo+1; for(int i=1;i<=n;i++) scanf("%d",&a[i]),pos[i]=(i-1)/blo+1; for(int i=n;i>0;i--){//逆序更新,因为前面的信息使用了后面的信息维护 if(i+a[i]>n) stp[i]=1,nxt[i]=n+1;//弹飞 else if(pos[i]==pos[i+a[i]]) stp[i]=stp[i+a[i]]+1,nxt[i]=nxt[i+a[i]];//块内 else stp[i]=1,nxt[i]=i+a[i];//块外 } cin>>m;}int main(){ init(); work(); return 0; }
LCT
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int M=200005;int n,m,y;int fa[M],c[M][2],st[M],sz[M],nxt[M];bool rev[M];inline bool f(int x){return c[fa[x]][1]==x;}inline bool isr(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}void pushup(int x){sz[x]=sz[c[x][0]]+sz[c[x][1]]+1;}void pushdown(int x){ if(!rev[x]) return ; int &l=c[x][0],&r=c[x][1]; rev[l]^=1;rev[r]^=1;swap(l,r); rev[x]=0;}void rotate(int x){ int p=fa[x],g=fa[p],r; bool k=f(x),m=f(p);r=c[x][k^1]; if(!isr(p)) c[g][m]=x; fa[x]=g,c[x][k^1]=p; fa[p]=x,c[p][k]=r; if(r) fa[r]=p; pushup(p);}void maintain(int x){ int top=0;st[++top]=x; for(int i=x;!isr(i);i=fa[i]) st[++top]=fa[i]; for(int i=top;i;i--) pushdown(st[i]);}void splay(int x){ maintain(x); for(;!isr(x);rotate(x)) if(!isr(fa[x])) rotate(f(x)==f(fa[x])?fa[x]:x); pushup(x);}void access(int x){for(y=0;x;c[x][1]=y,y=x,x=fa[x]) splay(x);}//取出当前点到当前根的这一段路径,将它们放到一个Splay中。void rever(int x){access(x);splay(x);rev[x]^=1;}//将x旋转到其所在树的树根 void link(int x,int y){rever(x);fa[x]=y;splay(x);}//将x连到y的下面 void cut(int x,int y){rever(x);access(y);splay(y);fa[x]=c[y][0]=0;}//断开x和y之间的边 void work(){ int opt,u,v; while(m--) { scanf("%d%d",&opt,&u);u++; if(opt==1) rever(n+1),access(u),splay(u),printf("%d\n",sz[c[u][0]]); if(opt==2) scanf("%d",&v),cut(u,nxt[u]),nxt[u]=min(u+v,n+1),link(u,nxt[u]); }}void init(){ int u; cin>>n; for(int i=1;i<=n;i++){ scanf("%d",&u); u=min(i+u,n+1); fa[i]=nxt[i]=u;sz[i]=1; } sz[n+1]=1; cin>>m;}int main(){ init(); work(); return 0;}
阅读全文
0 0
- BZOJ 2002: [Hnoi2010]Bounce 弹飞绵羊
- bzoj 2002: [Hnoi2010]Bounce 弹飞绵羊
- 【BZOJ 2002】 [Hnoi2010]Bounce 弹飞绵羊
- bzoj 2002: [Hnoi2010]Bounce 弹飞绵羊
- bzoj 2002: [Hnoi2010]Bounce 弹飞绵羊
- 2002: [Hnoi2010]Bounce 弹飞绵羊
- BZOJ 2002 Bounce 弹飞绵羊 [Hnoi2010]
- bzoj 2002: [Hnoi2010]Bounce 弹飞绵羊
- bzoj 2002: [Hnoi2010]Bounce 弹飞绵羊
- BZOJ 2002 [Hnoi2010]Bounce 弹飞绵羊
- BZOJ 2002 [Hnoi2010]Bounce 弹飞绵羊
- BZOJ 2002: [Hnoi2010]Bounce 弹飞绵羊
- BZOJ 2002: [Hnoi2010]Bounce 弹飞绵羊
- 2002: [Hnoi2010]Bounce 弹飞绵羊
- 2002: [Hnoi2010]Bounce 弹飞绵羊
- BZOJ 2002: [Hnoi2010]Bounce 弹飞绵羊
- [Hnoi2010]Bounce 弹飞绵羊
- [Hnoi2010]Bounce 弹飞绵羊
- jmeter的初步试用
- 树-堆结构练习——合并果子之哈夫曼树
- MySQL(1)--修改字符编码
- Einbahnstrasse HDU
- 文章标题
- 2002: [Hnoi2010]Bounce 弹飞绵羊
- 模糊查询
- 设计模式:各个模式间的对比
- 2.常用控件:RadioGroup和RadioButton
- 使用adb时,为什么只有RockChip的ID需要加入到adb_usb.ini文件里呢?
- 静态库和动态库
- hadoop、Storm该选哪一个
- listview加载跟多
- Git错误fatal: unable to access 'https://github.com/****.git/': Couldn't resolve host 'github.com'