JZOJ 4811. 排队(线段树的方法)

来源:互联网 发布:网络集成实施方案 编辑:程序博客网 时间:2024/06/06 05:20

Problem

Description

这里写图片描述

Input

这里写图片描述

Output

这里写图片描述

Sample Input

5 4
1 2
1 3
3 4
3 5
1 4
2 4
1 2
2 5

Sample Output

3
1
1
2

Data Constraint

这里写图片描述
这里写图片描述

Hint

这里写图片描述

Solution

之前有很多人用了来解决这个问题,现在我来讲一下线段树的方法。
我们先按照题意弄出一个优先序列order(就是先进哪个房间)。这个其实很好搞。
数组模拟链表一开始head显示的边是后面加进来的边,那么我们想先遍历的点的编号越小,那么我们可以按照这些边从大到小排,这样的话从head开始搜的边就是最小的,next之后越来越大(因为先加编号大的边,后加编号小的边)。
我们按order建立一棵线段树,来维护每段区间有多少个空位
先说操作2吧
对于每一个x,我们要找到它的一个祖先fa,这个祖先fa的父亲是空的。然后x与fa的深度差就是答案。然后fa这个房间空出来。下图是我对这个步骤的解释。
这里写图片描述
不要忘记将fa要在线段树里面空掉!
关键是操作1
我们要将order前面x个空的房间补满。我们尽量往左补,如果能够补完就补,不能补完就往右补直到补完为止。

void modify(int s,int l,int r,int x,bool p){    if (l==r)    {        tree[s]=0;        b[o[l]]=1;        if (p) mn=l;        return;    }    int wz=(l+r)/2,prd=tree[s*2];    if (prd>=x/*左边有空位*/) modify(s*2,l,wz,x,p);        else        {            modify(s*2,l,wz,prd,0);//将之前的空补满            modify(s*2+1,wz+1,r,x-prd,p);//向右搜        }    tree[s]=tree[s*2]+tree[s*2+1];}

至于什么倍增等的基础算法自己去实现。

Code

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#define N 100010#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)#define edge(i,x) for(i=head[x];i;i=next[i])using namespace std;int LCA,ans,x,y,i,j,cnt,n,t,op,tot,mn;int c[N*2][2],o[N],o1[N],deep[N],go[N*2],next[N*2],head[N*2],f[N][20],tree[N*10];bool b[N];void lb(int x,int y){    go[++tot]=y;    next[tot]=head[x];    head[x]=tot;}void bs(int x){    int i,now;    deep[x]=deep[f[x][0]]+1;    fo(i,1,log2(n)) if (f[x][i-1]) f[x][i]=f[f[x][i-1]][i-1];    edge(i,x)    {        now=go[i];        if (now==f[x][0]) continue;        f[now][0]=x;        bs(now);    }    o[++o[0]]=x;}void build(int s,int l,int r){    if (l==r)    {        tree[s]=1;        return;    }    int wz=(l+r)/2;    build(s*2,l,wz);    build(s*2+1,wz+1,r);    tree[s]=tree[s*2]+tree[s*2+1];}void modify(int s,int l,int r,int x,bool p){    if (l==r)    {        tree[s]=0;        b[o[l]]=1;        if (p) mn=l;        return;    }    int wz=(l+r)/2,prd=tree[s*2];    if (prd>=x) modify(s*2,l,wz,x,p);        else        {            modify(s*2,l,wz,prd,0);            modify(s*2+1,wz+1,r,x-prd,p);        }    tree[s]=tree[s*2]+tree[s*2+1];}void change(int s,int l,int r,int x){    if (l==r)    {        tree[s]=1;        return;    }    if (l==r) return;    int wz=(l+r)/2;    if (x<=wz) change(s*2,l,wz,x);          else change(s*2+1,wz+1,r,x);    tree[s]=tree[s*2]+tree[s*2+1];      }void qsort(int l,int r){    int i=l,j=r,m0=c[(l+r)/2][0],m1=c[(l+r)/2][1];    while (i<j)    {        while (c[i][0]>m0 || c[i][0]==m0 && c[i][1]>m1) i++;        while (c[j][0]<m0 || c[j][0]==m0 && c[j][1]<m1) j--;        if (i<=j)        {            swap(c[i],c[j]);            i++;j--;        }    }    if (l<j) qsort(l,j);    if (i<r) qsort(i,r);}int main(){    scanf("%d%d",&n,&t);    fo(i,1,n-1)    {        scanf("%d%d",&c[i][0],&c[i][1]);        if (c[i][0]>c[i][1]) swap(c[i][0],c[i][1]);    }    qsort(1,n-1);    fo(i,1,n-1) lb(c[i][0],c[i][1]),lb(c[i][1],c[i][0]);    bs(1);    fo(i,1,n) o1[o[i]]=i;    build(1,1,n);    fo(i,1,t)    {        scanf("%d%d",&op,&x);        if (op==1)        {            mn=0;            modify(1,1,n,x,1);            printf("%d\n",o[mn]);        } else        {            LCA=x;            fd(j,log2(n),0)                if (b[f[LCA][j]]) LCA=f[LCA][j];            b[LCA]=0;            ans=deep[x]-deep[LCA];            printf("%d\n",ans);            change(1,1,n,o1[LCA]);        }    }}
3 0