XJOI NOIP2016提高组冲剌题1 T3:排队
题目分析:
此题有两种操作:在结点处放置人,人被拿走后的统计影响的人数.
其实观察可以发现,第二种操作实际上就是讲将该点以上到第一个为空的祖先以下的所有点向下移动一个,倍增就很好解决,关键在于操作一的实现,暴力实现的话,需要把某一个人从根开始向下模拟放置,最坏情况下需要遍历整棵树.但是可以发现,实际上放置结点的顺序是一定的,即将人放置在某一个结点上,必定有放置顺序在它前面的点都已被放置,那么可以用堆来实现这个操作,先深搜一遍,求出其优先级,在堆中存放空结点即可.
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int logn=18;
const int maxn=100000+10;
int read()
{
char ch=getchar();int ret=0,flag=1;
while(ch<'0'||ch>'9') {if(ch=='-') flag=-1; ch=getchar();}
while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
return ret*flag;
}
vector<int>G[maxn];
int P[maxn],inq[maxn],pcnt;//P[i]表示i结点的优先级(此处值小的更优)
int anc[maxn][logn+2],n;
void dfs(int u,int fa)
{
anc[u][0]=fa;
int d=G[u].size();
for(int i=0;i<d;i++) if(G[u][i]!=fa) {
int v=G[u][i];dfs(v,u);
}
P[u]=++pcnt;
}
void init()
{
for(int i=1;i<=logn;i++)
for(int j=1;j<=n;j++)
anc[j][i]=anc[anc[j][i-1]][i-1];
}
int find(int x,int& ans)//倍增求第一个空祖先以前的结点数
{
for(int i=logn;x!=1&&i>=0;i--) if(anc[x][i]&&!inq[anc[x][i]])
x=anc[x][i],ans+=(1<<i);
return x;
}
struct Node {
int id;
Node(){}
Node(int id):id(id){}
bool operator < (const Node& rhs) const {
return P[id]>P[rhs.id];
}
};
int main()
{
n=read();int t=read();
for(int u,v,i=1;i<n;i++) {//用vector存储,方便排序
u=read();v=read();
G[u].push_back(v);
G[v].push_back(u);
}
for(int i=1;i<=n;i++) sort(G[i].begin(),G[i].end());
dfs(1,0);init();//深搜求优先级以及倍增初始化
priority_queue<Node>q;
for(int i=1;i<=n;i++) q.push(Node(i)),inq[i]=1;
while(t--) {
int op=read(),x=read(),ans=0;
if(op==1) {
Node u;
while(x--) {
u=q.top();q.pop();
inq[u.id]=0;
}
ans=u.id;
}
else {
int p=find(x,ans);
q.push(Node(p));inq[p]=1;
}
printf("%d\n",ans);
}
return 0;
}

本文解析了XJOINOIP2016提高组冲刺题1T3:排队问题,通过堆和倍增算法优化操作效率,解决了在结点处放置人及统计影响人数的问题。
824

被折叠的 条评论
为什么被折叠?



