[BZOJ5179] JSOI2011 任务调度

问题描述

一台超级计算机共有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

链接

BZOJ

解析

左偏树细节操作题。我们对每一个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;
}
posted @ 2020-01-30 22:55  CJlzf  阅读(284)  评论(3编辑  收藏  举报