P9754 [CSP-S 2023] 结构体
我是模拟大王,考场上想了两小时 T2 不会,一个小时写完这题过大样例了。
先把所有类型抽象成一个结点 node
,只需要维护其大小以及对齐信息。字符串的判断使用哈希实现。
接下来一个一个操作实现:
$1$ 操作
说人话就是新建一个点然后连一些边。算对齐信息是好做的,因为底下的结点我们都知道对齐信息;算空间也是好做的,因为底下的结点我们都知道空间大小,顺次递推即可,为了维护 $3,4$ 操作我们维护一个点每个子节点的空间左端点,存储在了 umap<int, pair<int, int>> sn
中,其中前者是字符串的哈希值,pair<int, int>
表示子结点编号以及在当前结点左端点为 $0$ 时,左端点的对齐信息。然后最后要把空间对齐到自己的对齐信息上。
$2$ 操作
开一个数组 w
表示当前声明了的结点实例的 node
编号,beg
表示声明了的每个实例的左端点。暴力维护即可。
$3$ 操作
一个一个跳,每次加上当前结点的左端点编号即为全局左端点。
$4$ 操作
跟 $3$ 操作差不多,模仿平衡树思想,一个一个判断 $addr$ 是否在当前区间内,是的话就往下跳,找不到往下就输出 ERR
。
考场代码
#include <bits/stdc++.h>
#define int long long
#define umap unordered_map
using namespace std;
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
struct node {
int siz, lim;
node() = default;
node(int s, int l): siz(s), lim(l) {}
};
int T;
node tr[maxn];
int tot;
umap<int, pair<int, int>> sn[maxn];
vector<int> snn[maxn];
umap<int, int> bk;
int hsh(string s) {
int y = 0;
for (int i = 0; i < s.length(); i++) y = (y * 251 % mod + s[i]) % mod;
return y;
}
int w[maxn];
int cnt;
umap<int, int> ck;
int beg[maxn];
string eriri[maxn];
int now;
umap<int, string> bas;
signed main() {
//freopen("struct.in", "r", stdin);
//freopen("struct.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
bk[557350929] = 1;
bk[101086854] = 2;
bk[6642831] = 3;
bk[714851925] = 4;
tr[1].siz = tr[1].lim = 1;
tr[2].siz = tr[2].lim = 2;
tr[3].siz = tr[3].lim = 4;
tr[4].siz = tr[4].lim = 8;
tot = 4;
cin >> T;
while (T--) {
int op;
cin >> op;
if (op == 1) {
string s, t, nam;
int k;
cin >> s >> k;
int u = ++tot;
bk[hsh(s)] = u;
int cur = 0;
for (int i = 1; i <= k; i++) {
cin >> t >> nam;
int v = bk[hsh(t)];
cur = (cur + tr[v].lim - 1) / tr[v].lim * tr[v].lim;
sn[u][hsh(nam)] = {v, cur};
snn[u].push_back(hsh(nam));
bas[hsh(nam)] = nam;
// cout << u << "->" << nam << " (" << v << " " << cur << ")" << endl;
cur += tr[v].siz;
tr[u].lim = max(tr[u].lim, tr[v].lim);
}
cur = (cur + tr[u].lim - 1) / tr[u].lim * tr[u].lim;
tr[u].siz = cur;
cout << tr[u].siz << " " << tr[u].lim << endl;
} else if (op == 2) {
string s, t;
cin >> s >> t;
w[++cnt] = bk[hsh(s)];
eriri[cnt] = t;
ck[hsh(t)] = cnt;
now = (now + tr[w[cnt]].lim - 1) / tr[w[cnt]].lim * tr[w[cnt]].lim;
cout << now << endl;
beg[cnt] = now;
now += tr[w[cnt]].siz;
} else if (op == 3) {
string s;
cin >> s;
vector<int> path;
int sta = 0;
for (int i = 0; i < s.length(); i++) {
if (s[i] == '.') {
int ter = i - 1;
path.push_back(hsh(s.substr(sta, ter - sta + 1)));
// cout << sta << " " << ter << endl;
sta = i + 1;
}
}
// cout << sta << " " << s.length() - 1 << endl;
path.push_back(hsh(s.substr(sta, s.length() - sta)));
int u = w[ck[path[0]]], pos = beg[ck[path[0]]];
for (int i = 1; i < path.size(); i++) {
pos += sn[u][path[i]].second;
// cout << u << endl;
u = sn[u][path[i]].first;
}
cout << pos << endl;
} else if (op == 4) {
int add;
cin >> add;
int p = 0;
for (int i = cnt; i; i--) {
if (beg[i] <= add) {
p = i;
break;
}
}
if (!p || beg[p] + tr[w[p]].siz - 1 < add) {
cout << "ERR" << endl;
continue;
}
// cout << p << endl;
int u = w[p], nw = beg[p];
string aaans = eriri[p];
while (true) {
if (u <= 4) {
cout << aaans << endl;
break;
}
bool fl = 0;
for (int h : snn[u]) {
// cout << u << "-" << bas[h] << "->" << sn[u][h].first << " " << sn[u][h].second << " " << tr[sn[u][h].first].siz << " " << nw << endl;
if (sn[u][h].second + nw <= add && sn[u][h].second + nw + tr[sn[u][h].first].siz > add) {
nw += sn[u][h].second;
aaans += ".";
aaans += bas[h];
fl = 1;
u = sn[u][h].first;
break;
}
}
if (!fl) {
cout << "ERR" << endl;
break;
}
}
}
}
return 0;
}
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现