问题描述
一台超级计算机共有N颗CPU。现在这台超级计算机有M个任务要做,但同时还要考虑到不能让CPU过热。所幸的是这台超级计算机已经将任务安排好了,现在要做的只是请你根据安排好的指令来模拟它的工作过程。一开始,这N颗CPU都没有被分配任何的任务。之后,会给你以下几类指令(CPU的编号为1到N的整数,任务的编号为1到M的整数)
指令格式 作用
ADD n k w 将 k 号任务(权值为 w)分配给 n 号 CPU
DEC n k w 将 k 号任务的权值减少 w(已知 k 号任务被分配给了 n 号 CPU)
TRANS n1 n2 将分配给 n1 号 CPU 的任务全部转移给 n2 号 CPU
MIN n 输出分配给 n 号 CPU 的任务中权值最小的任务的权值
WORK n w 将分配给 n 号 CPU 的任务中权值最小的任务的权值加上 w,如果权值最小的任务不唯一,则不更 改权值,并输出一行“ ERROR”
输入格式
包含N+1行。
第1行包含三个正整数N、M、K,分别表示CPU的数目、任务数和指令数。
第2行到K+1行,每行包含一条指令。
N≤500, M≤300000, K≤300000。
保证任务的权值在 32 位有符号整型的范围内。
保证一个任务只会被分配一次(即至多被 ADD 一次)。
保证 ADD 指令、DEC 指令和 WORK 指令中的 w 是非负整数。
保证 TRANS 指令的两个参数不相同。
输出格式
若干行,其中包括MIN语句的输出和“ERROR”输出,每个输出占一行
样例输入
2 3 13
ADD 1 2 100
ADD 1 1 90
MIN 1
WORK 1 20
TRANS 1 2
MIN 2
ADD 1 3 105
TRANS 2 1
MIN 1
DEC 1 3 200
MIN 1
DEC 1 1 205
WORK 1 15
样例输出
90
100
100
-95
ERROR
链接
解析
左偏树细节操作题。我们对每一个CPU维护一个小根可并堆,对于每一个操作,我们有如下做法:
ADD操作:就是正常的往可并堆中加入一个数。
DEL操作:可以这么做,首先把k节点从左偏树中抠出来,即把他的两个儿子合并后接到k节点的父亲上(k是根节点时例外)。然后对k的权值进行修改,再把他加入原来所在的堆中。
TRANS操作:即将n1合并到n2去,并把n1对应的堆设为0。
MIN操作:查询堆顶元素值即可。
WORK操作:相当于DEL操作,只需要细微的修改。注意,如果n的最小值与任意一个儿子所在的树中的最小值相等,说明最小值不止一个,需要输出ERROR。
代码
#include <iostream>
#include <cstdio>
#define N 502
#define M 300002
using namespace std;
char op[10];
int n,m,k,i,val[M],son[M][2],dis[M],fa[M],r[N];
int merge(int x,int y)
{
if(!x) return y;
if(!y) return x;
if(val[x]>val[y]) swap(x,y);
son[x][1]=merge(son[x][1],y);
if(dis[son[x][0]]<dis[son[x][1]]) swap(son[x][0],son[x][1]);
fa[son[x][0]]=fa[son[x][1]]=x;
dis[x]=dis[son[x][1]]+1;
return x;
}
void add(int x,int y,int z)
{
int f=fa[y],tmp=merge(son[y][0],son[y][1]);
if(r[x]==y) r[x]=tmp;
else if(son[f][0]==y) son[f][0]=tmp;
else son[f][1]=tmp;
fa[tmp]=f;
fa[y]=son[y][0]=son[y][1]=0;
val[y]+=z;
r[x]=merge(r[x],y);
}
int main()
{
scanf("%d %d %d",&n,&m,&k);
for(i=1;i<=k;i++){
int x,y,z;
scanf("%s",op);
if(op[0]=='A'){
scanf("%d %d %d",&x,&y,&z);
val[y]=z;
r[x]=merge(r[x],y);
}
else if(op[0]=='D'){
scanf("%d %d %d",&x,&y,&z);
add(x,y,-z);
}
else if(op[0]=='T'){
scanf("%d %d",&x,&y);
r[y]=merge(r[x],r[y]);
r[x]=0;
}
else if(op[0]=='M'){
scanf("%d",&x);
printf("%d\n",val[r[x]]);
}
else{
scanf("%d %d",&x,&y);
if((son[r[x]][0]&&val[r[x]]==val[son[r[x]][0]])||(son[r[x]][1]&&val[r[x]]==val[son[r[x]][1]])) puts("ERROR");
else add(x,r[x],y);
}
}
return 0;
}