列表

详情


NC19776. 数组合并

描述

有 N 个整数数组,将他们按照这样的步骤合并:
* 从所有非空数组的第一个元素中选最小的那个,从它所在的数组中删去并加入到输出数组的末尾
* 重复执行上述过程,直到所有数组为空。
很显然,如果所有数组都是有序的,你得到的数组也会是有序的。
现在你知道这 N 个数组的值,需要实现这样一个算法,支持对数组的修改和查询。
* 对于一个修改操作,给定两个参数 x, y,表示将数组中的 x 替换成 y 。在操作前和操作后都保证同一个数字最多出现一次。
* 对于一个查询操作,给定一个参数 x,表示查询合并后的数组从 x 位开始的 K 个数字。
聪明的你一定能出色的完成这道题!

输入描述

第一行三个整数 N, M, K.
接下来 N 行描述 N 个数组,每行以一个整数 n 开始,表示这个数组的元素个数,后面接 n 个整数 a1, ..., an. 注意,这里 a1, ..., an 以大写16进制表示,每个数字长度不超过4。
接下来 M 行描述 M 个操作,满足下面两种形式之一:
* "U x y"(不含引号)。表示一次修改操作。x, y 以大写16进制的形式给出,长度不超过4.
* "Q x"(不含引号)。表示一次查询操作。x 以大写16进制的形式给出,长度不超过4.

输出描述

对于每个询问操作,输出合并后的数组从第 x 项开始的最多 K 个元素,以空格隔开,用大写16进制表示,注意不要有前导零。

示例1

输入:

2 5 3
2 4 2
3 6 A 1
Q 3
U 1 F
Q 4
U F 1
Q 1

输出:

6 A 1
A F
4 2 6

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 202ms, 内存消耗: 44512K, 提交时间: 2019-02-28 11:06:52

# include <bits/stdc++.h>
using namespace std;
 
int s[1<<20][8], mx[1<<20];
const int M = 1 << 19;
const int G = 1 << 20;
bool debug;
 
int K, Q, step;
 
#define rep(i, n) for(int i = 0; i < n; ++i)
#define arr_sum(arr) accumulate(arr, arr + 8, 0)
 
int len[8];
int lim, key, cur[8];
void query() {
 static int tmp[8];
 rep(i, K) cur[i] = tmp[i] = len[i];
 int l = 0, r = M, mid, u = 1;
 key = 0;
 while(r - l > 1) {
  mid = (l + r) >> 1;
  rep(i, K) tmp[i] = min(cur[i], s[u<<1|1][i]);
  if(arr_sum(tmp) >= lim) {
   u = u << 1, r = mid;
   rep(i, K) cur[i] = tmp[i];
  } else {
   key = max(key, mx[u<<1]);
   u = u << 1 | 1, l = mid;
  }
 }
 key = max(key, mx[u]);
}
 
void update(int x,int i,int j) {
 if(j == G) {
  mx[M + x] = -1;
  s[M + x][i] = len[i];
 } else {
  mx[M + x] = x;
  s[M + x][i] = j;
 }
 for(int u = (M + x) >> 1; u; u = u >> 1) {
  s[u][i] = min(s[u << 1][i], s[u << 1 | 1][i]);
  mx[u] = max(mx[u << 1], mx[u << 1 | 1]);
 }
}
 
int vid[1<<19], vpo[1<<19], _val[1<<19], *val[8];
void simulate() {
 int k = vid[key], p = vpo[key];
 p += lim - 1 - (arr_sum(cur) - cur[k] + p);
 printf("%X", val[k][p]);
 cur[k] = p + 1;
 for(int _ = 1; _ < step; ++_) {
  k = -1;
  rep(i, K) if(cur[i] < len[i] && (k == -1 || val[i][cur[i]] < val[k][cur[k]])) k = i;
  if(k == -1) break;
  printf(" %X", val[k][cur[k]]);
  cur[k]++;
 }
 puts("");
}
 
int main() {
 scanf("%d%d%d", &K, &Q, &step);
 int *cur = _val;
 rep(i, K) {
  int cnt; scanf("%d", &cnt);
  len[i] = cnt; val[i] = cur;
  cur += cnt + (16 - cnt % 16);
  rep(j, cnt) {
   int x; scanf("%X", &x);
   assert(x < (1<<19));
   vid[x] = i;
   vpo[x] = j;
   val[i][j] = x;
  }
 }
 // init for segment tree
 rep(i, M) mx[i+M] = -1;
 rep(i, M) rep(j, K) s[i+M][j] = len[j];
 rep(i, K) rep(j, len[i]) {
  int x = val[i][j];
  mx[M + x] = x;
  s[M + x][i] = j;
 }
 for(int i = M - 1; i; --i) {
  mx[i] = max(mx[i<<1], mx[i<<1|1]);
  rep(j, K) s[i][j] = min(s[i<<1][j], s[i<<1|1][j]);
 }
 // operations
 int qid = 0;
 while(Q--) {
  char op[8];
  scanf("%s", op);
  if(op[0] == 'Q') {
   scanf("%d", &lim);
   qid += 1;
   debug = (qid == 317);
   query();
   simulate();
  } else {
   int x, y; scanf("%X%X", &x, &y);
   assert(x < (1<<19));
   assert(y < (1<<19));
   int i = vid[x], j = vpo[x];
   update(x, i, G);
   update(y, i, j);
   vid[y] = i;
   vpo[y] = j;
   val[i][j] = y;
  }
 }
}

C++11(clang++ 3.9) 解法, 执行用时: 282ms, 内存消耗: 48608K, 提交时间: 2019-01-07 19:01:12

# include <bits/stdc++.h>
using namespace std;

int s[1<<20][8], mx[1<<20];
const int M = 1 << 19;
const int G = 1 << 20;
bool debug;

int K, Q, step;

#define rep(i, n) for(int i = 0; i < n; ++i)
#define arr_sum(arr) accumulate(arr, arr + 8, 0)

int len[8];
int lim, key, cur[8];
void query() {
 static int tmp[8];
 rep(i, K) cur[i] = tmp[i] = len[i];
 int l = 0, r = M, mid, u = 1;
 key = 0;
 while(r - l > 1) {
  mid = (l + r) >> 1;
  rep(i, K) tmp[i] = min(cur[i], s[u<<1|1][i]);
  if(arr_sum(tmp) >= lim) {
   u = u << 1, r = mid;
   rep(i, K) cur[i] = tmp[i];
  } else {
   key = max(key, mx[u<<1]);
   u = u << 1 | 1, l = mid;
  }
 }
 key = max(key, mx[u]);
}

void update(int x,int i,int j) {
 if(j == G) {
  mx[M + x] = -1;
  s[M + x][i] = len[i];
 } else {
  mx[M + x] = x;
  s[M + x][i] = j;
 }
 for(int u = (M + x) >> 1; u; u = u >> 1) {
  s[u][i] = min(s[u << 1][i], s[u << 1 | 1][i]);
  mx[u] = max(mx[u << 1], mx[u << 1 | 1]);
 }
}

int vid[1<<19], vpo[1<<19], _val[1<<19], *val[8];
void simulate() {
 int k = vid[key], p = vpo[key];
 p += lim - 1 - (arr_sum(cur) - cur[k] + p);
 printf("%X", val[k][p]);
 cur[k] = p + 1;
 for(int _ = 1; _ < step; ++_) {
  k = -1;
  rep(i, K) if(cur[i] < len[i] && (k == -1 || val[i][cur[i]] < val[k][cur[k]])) k = i;
  if(k == -1) break;
  printf(" %X", val[k][cur[k]]);
  cur[k]++;
 }
 puts("");
}

int main() {
 scanf("%d%d%d", &K, &Q, &step);
 int *cur = _val;
 rep(i, K) {
  int cnt; scanf("%d", &cnt);
  len[i] = cnt; val[i] = cur;
  cur += cnt + (16 - cnt % 16);
  rep(j, cnt) {
   int x; scanf("%X", &x);
   assert(x < (1<<19));
   vid[x] = i;
   vpo[x] = j;
   val[i][j] = x;
  }
 }
 // init for segment tree
 rep(i, M) mx[i+M] = -1;
 rep(i, M) rep(j, K) s[i+M][j] = len[j];
 rep(i, K) rep(j, len[i]) {
  int x = val[i][j];
  mx[M + x] = x;
  s[M + x][i] = j;
 }
 for(int i = M - 1; i; --i) {
  mx[i] = max(mx[i<<1], mx[i<<1|1]);
  rep(j, K) s[i][j] = min(s[i<<1][j], s[i<<1|1][j]);
 }
 // operations
 int qid = 0;
 while(Q--) {
  char op[8];
  scanf("%s", op);
  if(op[0] == 'Q') {
   scanf("%d", &lim);
   qid += 1;
   debug = (qid == 317);
   query();
   simulate();
  } else {
   int x, y; scanf("%X%X", &x, &y);
   assert(x < (1<<19));
   assert(y < (1<<19));
   int i = vid[x], j = vpo[x];
   update(x, i, G);
   update(y, i, j);
   vid[y] = i;
   vpo[y] = j;
   val[i][j] = y;
  }
 }
}

上一题