题解分享
题解分享简介
小风的冒险者任务调度 - 题解
小风的冒险者任务调度
tag
数据结构(树状数组,线段树),模拟
题意简述
对于一个长度为 $n$ 的自然排列,执行 $m$ 次操作,每次操作可以选择一个数,将他移动到排列的最前方。求每个数在排列中出现过的最靠前位置和最靠后位置。
fun fact
赛时看到这题,第一时间想到了平衡树,然后打了一个无旋treap,但是发现treap只能按排名分裂,而本题是找到数本身再操作,然后又想了好久的如何维护排名,最后想到了树状数组维护排名,然后就打了一个树状数组维护每个数的排名+无旋treap维护每个数的最前和最后位置。把题打完之后,突然意识到,树状数组维护排名,答案不就可以直接统计了吗?直接更新就行,为什么要用treap呢?QAQ
题解思路
首先,需要注意到一点:每个数的最小排名只会有两种情况:1或者它本身,对于每次操作,如果对象是这个数,那么它的最小排名就会变成 $1$ ,否则他的排名一定不会变得更优。所以,最小排名只需要看他是否被操作过就行,没操作就是它本身,操作过就是 $1$。难点在于如何维护最大排名。我们思考排名的本质:有多少个数的位置在他的前面。也就是我们可以用权值树状数组维护每个数的位置,一个数的排名就是 $pos_i$ 的前缀和。
然后再来考虑处理操作,想到权值树状数组维护维护位置,每次操作本质上是把一个数的位置移动到所有数的前面,我们可以在权值树状数组的前面预留出 $m$ 个位置,每次操作就把数的权值移动到前面的位置,然后更新答案即可。
参考代码
```cpp
vector<pii> ans(N + 1);
int bit[N * 2];
void add(int pos, int x)
{
for(; pos < N * 2; pos += (pos & -pos)) bit[pos] += x;
}
int query(int pos)
{
int res = 0;
for(; pos; pos -= (pos & -pos)) res += bit[pos];
return res;
}
signed main()
{
IOS;
int n, m;
cin >> n >> m;
vector<int> pos(n + m + 1);
for(int i = 1; i <= n; i ++)
{
// 预留出前面 m 个位置,所有数往后偏移 m
pos[i] = m + i;
add(pos[i], 1);
ans[i].first = ans[i].second = i;
}
// 倒着放前面预留的位置
for(int i = m; i >= 1; i --)
{
int p;
cin >> p;
ans[p].first = 1;
int rk = query(pos[p]);
// 一个数被提前,他原来的排名可能会成为最大排名,更新答案
ans[p].second = max(ans[p].second, rk);
add(pos[p], -1);
pos[p] = i;
add(pos[p], 1);
}
for(int i = 1; i <= n; i ++)
{
// 最后所有数确定好之后再更新一次答案
ans[i].second = max(ans[i].second, query(pos[i]));
cout << ans[i].first << ' ' << ans[i].second << '\n';
}
}
```
赛时写的抽象东西(逃)
ps:不要这样做QAQ
```cpp
vector<pii> ans(N + 1);
struct fhq_treap
{
struct node
{
int l, r;
int size;
unsigned key;
int val;
int min, max;
int tag;
node() {tag = val = size = key = l = r = 0;}
node(int val, int size,int key) : val(val), size(size), key(key), min(val), max(val) {tag = l = r = 0;}
};
vector<node> tr;
random_device rd;
mt19937 rng;
int root;
fhq_treap()
{
root = 0;
tr.resize(1);
rng = mt19937(rd());
}
int create(int v)
{
int u = tr.size();
tr.push_back(node(v, 1, rng()));
return u;
}
void pushup(int u)
{
tr[u].size = tr[tr[u].l].size + tr[tr[u].r].size + 1;
tr[u].max = max(tr[u].max, tr[u].val);
}
void pushdown(int u)
{
if (tr[u].tag)
{
tr[tr[u].l].val += tr[u].tag;
tr[tr[u].l].tag += tr[u].tag;
tr[tr[u].r].val += tr[u].tag;
tr[tr[u].r].tag += tr[u].tag;
tr[u].tag = 0;
}
}
void split_by_val(int u, int val, int &x, int &y)
{
if (!u)
{
x = y = 0;
return;
}
if (tr[u].val <= val)
{
x = u;
split_by_val(tr[x].r, val, tr[u].r, y);
}
else
{
y = u;
split_by_val(tr[u].l, val, x, tr[u].l);
}
pushup(u);
}
void split_by_rank(int u, int rank, int &x, int &y)
{
if (!u)
{
x = y = 0;
return;
}
pushdown(u);
if (rank > tr[tr[u].l].size)
{
rank -= tr[tr[u].l].size + 1;
x = u;
split_by_rank(tr[u].r, rank, tr[u].r, y);
}
else
{
y = u;
split_by_rank(tr[u].l, rank, x, tr[u].l);
}
pushup(u);
}
int merge(int x, int y)
{
if (!x || !y)
return x + y;
if (tr[x].key < tr[y].key)
{
pushdown(x);
tr[x].r = merge(tr[x].r, y);
pushup(x);
return x;
}
else
{
pushdown(y);
tr[y].l = merge(x, tr[y].l);
pushup(y);
return y;
}
}
void insert(int val)
{
int z = create(val);
int x, y;
split_by_val(root, val, x, y);
root = merge(merge(x, z), y);
}
void del(int val)
{
int x, y, z;
split_by_val(root, val, x, z);
split_by_val(x, val - 1, x, y);
y = merge(tr[y].l, tr[y].r);
root = merge(merge(x, y), z);
}
int get_rank(int u, int k) // 获取排名为k的树
{
if (k <= tr[tr[u].l].size)
return get_rank(tr[u].l, k);
else if (k == tr[tr[u].l].size + 1)
return tr[u].val;
else
return get_rank(tr[u].r, k - tr[tr[u].l].size - 1);
}
int rank(int val) // 获取val的排名
{
int x, y;
split_by_val(root, val - 1, x, y);
int res = tr[x].size + 1;
merge(x, y);
return res;
}
int pre(int val)
{
int x, y;
split_by_val(root, val - 1, x, y);
int res = get_rank(x, tr[x].size);
root = merge(x, y);
return res;
}
int suc(int val)
{
int x, y;
split_by_val(root, val, x, y);
int res = get_rank(y, 1);
root = merge(x, y);
return res;
}
node &operator[](int idx)
{
return tr[idx];
}
void inorder(int u)
{
pushdown(u);
if(tr[u].l != 0) inorder(tr[u].l);
if(tr[u].r != 0) inorder(tr[u].r);
pushup(u);
ans[u] = {tr[u].min, tr[u].max};
}
};
int bit[N * 2];
void add(int pos, int x)
{
for(; pos < N * 2; pos += (pos & -pos)) bit[pos] += x;
}
int query(int pos)
{
int res = 0;
for(; pos; pos -= (pos & -pos)) res += bit[pos];
return res;
}
signed main()
{
IOS;
int n, k;
cin >> n >> k;
fhq_treap fhq;
vector<int> pos(n + k + 1);
for(int i = 1; i <= n; i ++)
fhq.insert(i), pos[i] = n - i + 1, add(pos[i], 1);
for(int i = 1; i <= k; i ++)
{
int p;
cin >> p;
int rk = query(n + k + 1) - query(pos[p] - 1);
add(pos[p], -1);
pos[p] = n + i;
add(pos[p], 1);
int x = 0, y = 0, z = 0;
fhq.split_by_rank(fhq.root, rk, x, y);
fhq.split_by_rank(x, rk - 1, x, z);
fhq[x].val += 1;
fhq[x].tag += 1;
fhq[z].val = fhq[z].min = 1;
fhq.root = fhq.merge(z, fhq.merge(x, y));
}
fhq.inorder(fhq.root);
for(int i = 1; i <= n; i ++)
{
cout << ans[i].first << ' ' << ans[i].second << '\n';
}
}
```
查看全文
0
0
1
7



