BZOJ 2002 弹飞绵羊

某天全是数据结构的考试题T3

在我学LCT之前就在轩神的博客中看到过这个归类在LCT里,所以事先知道了算法,不过这个貌似也挺明显的。(虽然分块更好写)

考场上为了证明哇我会写LCT诶就强行打了只打过一遍的LCT,然后Debug两个小时。。。最后还一不小心交了一个没debug的版本。。

//Twenty  debug两个小时 
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#define lc ch[x][0]
#define rc ch[x][1]
using namespace std;
const int maxn=2e5+299;
int opt,xx,yy,zz,k[maxn],sz[maxn],p[maxn],ch[maxn][2],flip[maxn],n,m;
inline int read(){
   int ret=0,f=1; char ch=getchar();
   while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
   if(ch=='-') f=-1,ch=getchar();
   for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
   return ret*f;
}
void update(int x) {sz[x]=sz[lc]+sz[rc]+1;}
bool isroot(int x) {return (ch[p[x]][1]!=x&&ch[p[x]][0]!=x);}
void build(int i,int x){
   k[i]=x;
   sz[i]=1;
   if(i+k[i]<=n) p[i]=i+k[i];
   else p[i]=n+1; 
}
void rotate(int x){
    int y=p[x],z=p[y],l=(x==ch[y][1]),r=l^1;
    if(!isroot(y)) ch[z][y==ch[z][1]]=x; p[x]=z;
    ch[y][l]=ch[x][r]; p[ch[y][l]]=y;
    ch[x][r]=y; p[y]=x;
    update(y); update(x);
}
void splay(int x){
   for(;!isroot(x);rotate(x)){
    int y=p[x],z=p[y];
    if(!isroot(y)) ((x==ch[y][1])^(y==ch[z][1]))?rotate(x):rotate(y);
   }
}
void access(int x){
   for(int t=0;x;x=p[t=x]){
    splay(x);
    rc=t;
    update(x);
   }
}
void cut(int a,int b){
   access(b);
   splay(b);
   p[ch[b][0]]=0;ch[b][0]=0;//p[a]=0; 多了假根 a不一定是左儿子 
   update(b);
}
int main()
{
   freopen("bounce.in","r",stdin);
   freopen("bounce.out","w",stdout);
   n=read(); 
   for(int i=1;i<=n;i++) build(i,read());
   m=read(); sz[n+1]=1;//若将根点sz设为0  update时会出错 ,若不设根点翻转时似乎会出一些不可言喻的错 
   while(m--){
    opt=read(); xx=read();xx++;
    if(opt==1){
        access(xx);
        splay(xx);
        printf("%d\n",sz[xx]-1);
    }
    else{
     yy=read();
     /*if(xx+k[xx]<=n&&xx+yy<=n) cut(xx+k[xx],xx);
     //else cut(n+1,xx);  //若将根Cut会出现不可言喻的错误 
     if(xx+yy<=n) p[xx]=xx+yy;
     //else p[xx]=n+1;
     else if(xx+k[xx]<=n) p[xx]=n+1;
     k[xx]=yy; */  //这个把不是假根改成是假根就错了。。。。 
      int now=min(n+1,yy+xx),last=min(k[xx]+xx,n+1);
      if(now!=last){
        cut(last,xx);
        p[xx]=now;
        k[xx]=yy;
      } 
    }
   }
   return 0;
}
弹飞绵羊

另两种写法以后什么时候再来填坑把。

 

 -------------------------------------------------更新---------------------------------------------------

2.分块

第一次写这样的分块吧,之前打的分块都是乱搞一些线段树的题基本。每个点维护跳出块需要多少步和跳到的点。每次修改就暴力修改一个块内的该点前面的部分。

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int maxn=200000+299;
int n,m,fa[maxn],belong[maxn],nxt[maxn],step[maxn],gs,o,x,y;
void modify(int x,int y) {
    if(belong[x]!=belong[y]) {
        nxt[x]=y;
        step[x]=1;
    }
    else {
        step[x]=step[y]+1;
        nxt[x]=nxt[y];
    }
}
int main() {
    scanf("%d",&n);
    for(int i=0;i<n;i++) {
        scanf("%d",&fa[i]);
        fa[i]=min(i+fa[i],n);
    }
    gs=sqrt(2*n)+1;
    for(int i=0;i<n;i++) 
        belong[i]=i/gs;
    belong[n]=-1;
    for(int i=n-1;i>=0;i--) modify(i,fa[i]);
    scanf("%d",&m);
    for(int i=1;i<=m;i++) {
        scanf("%d%d",&o,&x);
        if(o==1) {
            int tp=x,ans=0;
            while(tp!=n) {
                ans+=step[tp];
                tp=nxt[tp];
            }
            printf("%d\n",ans);
        }
        else {
            scanf("%d",&fa[x]);
            fa[x]=min(fa[x]+x,n);
            for(int i=x;i>=0&&belong[i]==belong[x];i--)
                modify(i,fa[i]);
        }
    }
    return 0;
}
View Code

 

---------------------------------------------2018-3-7更新---------------------------------------

现在看以前的博客觉得自己真的好蠢啊。。

时隔多年来补splay维护括号序列的写法。

看代码就能理解,没什么好说的。自底向上的splay真是奥妙重重。

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
const int N=400007;
typedef long long LL;
using namespace std;
int n,m;

template<typename T>void read(T &x)  {
    char ch=getchar(); x=0; T f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

int ecnt,fir[N],nx[N],to[N];
void add(int u,int v) {
    nx[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
}

int dfs_clock,dfn[2][N],v[N];
void dfs(int x) {
    v[dfn[0][x]=++dfs_clock]=1;
    for(int i=fir[x];i;i=nx[i]) 
        dfs(to[i]);
    v[dfn[1][x]=++dfs_clock]=-1;
}

int tot,p[N],sum[N],ch[N][2];
#define lc ch[x][0]
#define rc ch[x][1]
void update(int x) { sum[x]=v[x]; if(lc) sum[x]+=sum[lc]; if(rc) sum[x]+=sum[rc]; }

int build(int sz) {
    if(sz<=0) return 0;
    int ls=build(sz>>1);
    int x=++tot;
    int rs=build(sz-(sz>>1)-1);
    lc=ls; rc=rs;
    if(lc) p[lc]=x; 
    if(rc) p[rc]=x;
    update(x);
    return x;
}

void rotate(int x) {
    int y=p[x],z=p[y],l=(x==ch[y][1]),r=l^1;
    if(z) ch[z][y==ch[z][1]]=x; p[x]=z;
    ch[y][l]=ch[x][r]; p[ch[x][r]]=y;
    ch[x][r]=y; p[y]=x;
    update(y); update(x); 
}

void splay(int x) {
    for(;p[x];rotate(x)) {
        int y=p[x],z=p[y];
        if(z) ((x==ch[y][1])^(y==ch[z][1]))?rotate(x):rotate(y);
    }
}

int nxt(int x) {
    splay(x); x=rc;
    while(lc) x=lc;
    splay(x); return x;
}

int pre(int x) {
    splay(x); x=lc;
    while(rc) x=rc;
    splay(x); return x;
}

int split(int x) { //x作为左边最后一个 
    splay(x); int y=rc; 
    p[y]=rc=0;
    update(x); return y;
}

void merge(int x,int y) {
    splay(x); splay(y);
    while(rc) x=rc; splay(x);
    rc=y; p[y]=x; update(x);
} 

int main() {
    read(n);
    for(int i=1;i<=n;i++) {
        int fa; read(fa); 
        fa=min(fa+i,n+1); 
        add(fa,i);
    }
    dfs(n+1);
    int x=2*(n+1)+1,y=x+1;
    ch[x][1]=y; p[y]=x;
    ch[y][0]=build(2*(n+1));
    p[ch[y][0]]=y; tot=y; 
    update(y); update(x);
    read(m);
    while(m--) {
        int o,u,fa;
        read(o); read(u); u++;
        if(o==1) {
            int x=nxt(dfn[0][u]);
            printf("%d\n",sum[lc]-1);
        }
        else {
            read(fa); fa=min(fa+u,n+1);
            int l=pre(dfn[0][u]);
            split(l);
            int r=split(dfn[1][u]);
            merge(l,r);
            split(dfn[0][fa]);
            merge(dfn[0][fa],dfn[1][u]);
            merge(dfn[1][u],dfn[1][fa]);
        }
    }
    return 0;
}
/*
4                              
1 2 1 1                           
3
1 1
2 1 1
1 1
*/
View Code

 

posted @ 2017-09-04 19:03  啊宸  阅读(150)  评论(0编辑  收藏  举报