BZOJ3133: [Baltic2013]ballmachine

这道题(看题解)不难想到,如果只放球,小球依次滚下落到的位置一定是一个确定的序列(如样例中的序列为58637421),这个东西可以求(很多方法…….我是每个点子树排),然后每次放球其实可以一个一个球放,因为每次取球只会取一个,所以不会超时,于是放球就一个个在序列里找最左的空位放,取x位置的球时,找x的祖先中层数最上的非空位,就相当于取那个位置的球,这个可以用树剖求,其他方法求我不会(有什么好的办法可以评论教我)
所以维护两棵线段树就好了


code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

void read(int &x)
{
    char c;
    while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0';
}

const int maxn = 210000;
struct edge
{
    int y,nex;
    edge(){}
    edge(int _y,int _nex){y=_y;nex=_nex;}
}a[maxn]; int len,fir[maxn];
int n,m,rt;
int mn[maxn],que[maxn],tail,id[maxn];
int siz[maxn],son[maxn],fa[maxn],dep[maxn],top[maxn],w[maxn],wi[maxn],z;
void ins(int x,int y){ a[++len]=edge(y,fir[x]); fir[x]=len; }

void up(int &x,int y){if(y>x)x=y;}
void down(int &x,int y){if(y<x)x=y;}
void dfs(int x)
{
    siz[x]=1; son[x]=0;
    for(int k=fir[x];k;k=a[k].nex)
    {
        int y=a[k].y;
        fa[y]=x;
        dep[y]=dep[x]+1;
        dfs(y);
        siz[x]+=siz[y];
        if(siz[son[x]]<siz[y]) son[x]=y;
    }
}
void build_(int x,int tp)
{
    w[x]=++z; wi[z]=x; top[x]=tp;
    if(son[x]) build_(son[x],tp);
    for(int k=fir[x];k;k=a[k].nex)
    {
        int y=a[k].y;
        if(y!=son[x]) build_(y,y);
    }
}
struct node
{
    int x,c;
    node(){}
    node(int _x,int _c){x=_x;c=_c;}
}qm[maxn<<1];
bool cmp(node x,node y){return x.c<y.c;}
int head[maxn],tot[maxn],L;
void g1(int x)
{
    mn[x]=x;
    for(int k=fir[x];k;k=a[k].nex)
    {
        int y=a[k].y;
        g1(y);
        down(mn[x],mn[y]);
    }
    if(fir[x])
    {
        head[x]=L+1;
        for(int k=fir[x];k;k=a[k].nex)
        {
            int y=a[k].y;
            qm[++L]=node(y,mn[y]);
        }
        tot[x]=L-head[x]+1;
        sort(qm+head[x],qm+L+1,cmp);
    }
}
void g2(int x)
{
    if(fir[x])
    {
        int tt=head[x]+tot[x]-1;
        for(int i=head[x];i<=tt;i++) g2(qm[i].x);
    }
    que[++tail]=x;
    id[x]=tail;
}

int tr1[maxn<<2];
void build_t1(int x,int l,int r)
{
    tr1[x]=l;
    if(l==r) return ;
    int mid=(l+r)>>1;
    build_t1(x<<1,l,mid); build_t1((x<<1)+1,mid+1,r);
}
void push_up(int x)
{
    int lc=x<<1,rc=lc|1;
    if(tr1[lc]) tr1[x]=tr1[lc];
    else if(tr1[rc]) tr1[x]=tr1[rc];
    else tr1[x]=0;
}
int add(int x,int l,int r)
{
    if(l==r) { tr1[x]=0; return l; }
    int mid=(l+r)>>1,lc=x<<1,rc=lc|1,re;
    if(tr1[x]<=mid) re=add(lc,l,mid);
    else re=add(rc,mid+1,r);
    push_up(x); return re;
}
void del(int x,int l,int r,int loc)
{
    if(l==r) { tr1[x]=loc; return ; }
    int mid=(l+r)>>1,lc=x<<1,rc=lc|1;;
    if(loc<=mid) del(lc,l,mid,loc);
    else del(rc,mid+1,r,loc);
    push_up(x);
}

int tr2[maxn<<2];
void push_up2(int x)
{
    int lc=x<<1,rc=lc|1;
    if(tr2[lc]) tr2[x]=tr2[lc];
    else if(tr2[rc]) tr2[x]=tr2[rc];
    else tr2[x]=0;
}
void add2(int x,int l,int r,int loc)
{
    if(l==r) { tr2[x]=l; return ; }
    int mid=(l+r)>>1,lc=x<<1,rc=lc|1;
    if(loc<=mid) add2(lc,l,mid,loc);
    else add2(rc,mid+1,r,loc);
    push_up2(x);
}
void del2(int x,int l,int r,int loc)
{
    if(l==r) { tr2[x]=0; return ; }
    int mid=(l+r)>>1,lc=x<<1,rc=lc|1;
    if(loc<=mid) del2(lc,l,mid,loc);
    else del2(rc,mid+1,r,loc);
    push_up2(x);
}
int find_(int x,int l,int r,int lx,int rx)
{
    if(lx<=l&&r<=rx) return tr2[x];
    int mid=(l+r)>>1,lc=x<<1,rc=lc|1;
    if(rx<=mid) return find_(lc,l,mid,lx,rx);
    else if(lx>mid) return find_(rc,mid+1,r,lx,rx);
    else
    {
        int re=find_(lc,l,mid,lx,mid);
        if(!re) re=find_(rc,mid+1,r,mid+1,rx);
        return re;
    }
}
int solve(int x)
{
    int f1=top[x],re=0,la;
    while(x) 
    {
        re=find_(1,1,z,w[f1],w[x]);
        if(!re&&la) break;
        la=re;
        x=fa[f1]; f1=top[x];
    }
    re=wi[la];
    del2(1,1,z,w[re]);
    del(1,1,tail,id[re]);
    return re;
}

int main()
{
    memset(fir,0,sizeof fir); len=0;

    read(n); read(m);
    for(int i=1;i<=n;i++)
    {
        int x; read(x);
        if(x==0) rt=i;
        ins(x,i);
    }
    dfs(rt); build_(rt,rt);
    g1(rt); g2(rt);

    build_t1(1,1,tail);
    while(m--)
    {
        int x,y; read(x); read(y);
        if(x==1)
        {
            int re=0;
            while(y--)
            {
                re=add(1,1,tail);
                add2(1,1,z,w[que[re]]);
            }
            printf("%d\n",que[re]);
        }
        else
        {
            int re=solve(y);
            printf("%d\n",dep[y]-dep[re]);
        }
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值