排队
来源:互联网 发布:linux 查看局域网ip 编辑:程序博客网 时间:2024/05/01 07:09
题目描述
做法
我们先处理出fix表示在全空情况下不断进人,i这个房间被第几个人最终停留。
用一个堆保留空房间当前fix的最小值,每次进一个人就是选择堆中最小值的房间。
拿走人的话观察一下就是从这个房间往上有人房间的数量-1,这个可以倍增来求,因为这个房间到根路径上有人和没人一定是分离开的。
分析一下势能这样做是n log n的。
#include<cstdio>#include<algorithm>#include<set>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=100000+10;int f[maxn][25],fix[maxn],co[maxn],d[maxn],b[maxn*2],sta[100];int h[maxn],go[maxn*2],next[maxn*2];struct dong{ int id,fix; friend bool operator <(dong a,dong b){ return a.fix<b.fix; }};set<dong> s;dong zlt;int i,j,k,l,t,n,m,tot,top;int read(){ int x=0; char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while (ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x;}void add(int x,int y){ go[++tot]=y; next[tot]=h[x]; h[x]=tot;}void dfs(int x,int y){ f[x][0]=y; d[x]=d[y]+1; int i,t=h[x],l=top+1,r=top; while (t){ if (go[t]!=y) b[++r]=go[t]; t=next[t]; } sort(b+l,b+r+1); top=r; fo(i,l,r) dfs(b[i],x); top=l-1; fix[x]=++tot;}int getfather(int x){ int j=floor(log(n)/log(2)); while (j>=0){ if (co[f[x][j]]==1) x=f[x][j]; j--; } return x;}void write(int x){ if (!x){ putchar('0'); putchar('\n'); return; } top=0; while (x){ sta[++top]=x%10; x/=10; } while (top){ putchar('0'+sta[top]); top--; } putchar('\n');}int main(){ n=read();m=read(); fo(i,1,n-1){ j=read();k=read(); add(j,k);add(k,j); } top=tot=0; dfs(1,0); fo(j,1,floor(log(n)/log(2))) fo(i,1,n) f[i][j]=f[f[i][j-1]][j-1]; fo(i,1,n){ zlt.id=i; zlt.fix=fix[i]; s.insert(zlt); } while (m--){ t=read(); if (t==1){ k=read(); while (k--){ zlt=*s.begin(); co[zlt.id]=1; if (!k) write(zlt.id); s.erase(s.find(zlt)); } } else{ k=read(); if (!co[k]){ write(0); continue; } j=getfather(k); write(d[k]-d[j]); co[j]=0; zlt.id=j; zlt.fix=fix[j]; s.insert(zlt); } }}
0 0