ABC298解题报告
C. Cards Query Problem
题意:有一些盒子,每次操作有以下三种:把数 \(i\) 扔到集合 \(j\) 内;查询某个集合里的所有数(升序)(可重);查询包含某个数的集合(升序)(去重)。保证输出的数个数在 \(2\times 10^5\) 内。
可以维护两个 map 套 set,分别表示盒子的数和数的盒子,其中盒子的数用 multiset,数的盒子用 set。每次插入就同时往两个桶里扔,查询就输出一个桶即可。
By cxm1024
#include <bits/stdc++.h>
using namespace std;
signed main() {
int n, q;
scanf("%d%d", &n, &q);
map<int, multiset<int> > mp1;
map<int, set<int> > mp2;
while (q--) {
int op, x, y;
scanf("%d%d", &op, &x);
if (op == 1) {
scanf("%d", &y);
mp1[y].insert(x), mp2[x].insert(y);
}
else if (op == 2) {
for (int tmp : mp1[x])
printf("%d ", tmp);
puts("");
}
else {
for (int tmp : mp2[x])
printf("%d ", tmp);
puts("");
}
}
return 0;
}
同样可以使用 map 套 vector,每次输出时暴力排序(可能去重)后输出。因为输出总数的限制,所以复杂度不会有问题。
By noimi
int main() {
INT(n, q);
constexpr int N = 200001;
vector<vi> a(N), b(N);
rep(q) {
INT(t);
if(t == 1) {
INT(i, j);
a[j].eb(i);
b[i].eb(j);
} else if(t == 2) {
INT(i);
SORT(a[i]);
OUT(a[i]);
} else {
INT(i);
UNIQUE(b[i]);
OUT(b[i]);
}
}
}
也可以使用堆维护,本质相同。
By pengin
#include<stdio.h>
int cnt_box[400005], sum_cnt_box[400005];
int cnt_card[400005], sum_cnt_card[400005];
int h_box[400005], l_box[200005];
int h_card[400005], l_card[200005];
int comp_h_box(int a, int b)
{
if (h_box[a] > h_box[b])
return 1;
else
return -1;
}
int comp_h_card(int a, int b)
{
if (h_card[a] > h_card[b])
return 1;
else
return -1;
}
void swap_h_box(int a, int b)
{
int f = h_box[a];
h_box[a] = h_box[b];
h_box[b] = f;
return;
}
void swap_h_card(int a, int b)
{
int f = h_card[a];
h_card[a] = h_card[b];
h_card[b] = f;
return;
}
void push_box(int box, int ne)
{
h_box[l_box[box]] = ne;
int p = l_box[box];
l_box[box]++;
for (; p > sum_cnt_box[box]; p = (p - sum_cnt_box[box] - 1) / 2 + sum_cnt_box[box])
if (comp_h_box((p - sum_cnt_box[box] - 1) / 2 + sum_cnt_box[box], p) > 0)
swap_h_box((p - sum_cnt_box[box] - 1) / 2 + sum_cnt_box[box], p);
return;
}
void push_card(int card, int ne)
{
h_card[l_card[card]] = ne;
int p = l_card[card];
l_card[card]++;
for (; p > sum_cnt_card[card]; p = (p - sum_cnt_card[card] - 1) / 2 + sum_cnt_card[card])
if (comp_h_card((p - sum_cnt_card[card] - 1) / 2 + sum_cnt_card[card], p) > 0)
swap_h_card((p - sum_cnt_card[card] - 1) / 2 + sum_cnt_card[card], p);
return;
}
int pop_box(int box)
{
l_box[box]--;
swap_h_box(sum_cnt_box[box], l_box[box]);
int p = sum_cnt_box[box];
for (;;)
{
if (2 * (p - sum_cnt_box[box]) + 2 + sum_cnt_box[box] < l_box[box])
{
if (comp_h_box(2 * (p - sum_cnt_box[box]) + 1 + sum_cnt_box[box], 2 * (p - sum_cnt_box[box]) + 2 + sum_cnt_box[box]) > 0)
{
if (comp_h_box(p, 2 * (p - sum_cnt_box[box]) + 2 + sum_cnt_box[box]) > 0)
swap_h_box(p, 2 * (p - sum_cnt_box[box]) + 2 + sum_cnt_box[box]);
p = 2 * (p - sum_cnt_box[box]) + 2 + sum_cnt_box[box];
}
else
{
if (comp_h_box(p, 2 * (p - sum_cnt_box[box]) + 1 + sum_cnt_box[box]) > 0)
swap_h_box(p, 2 * (p - sum_cnt_box[box]) + 1 + sum_cnt_box[box]);
p = 2 * (p - sum_cnt_box[box]) + 1 + sum_cnt_box[box];
}
}
else if (2 * (p - sum_cnt_box[box]) + 1 + sum_cnt_box[box] < l_box[box])
{
if (comp_h_box(p, 2 * (p - sum_cnt_box[box]) + 1 + sum_cnt_box[box]) > 0)
swap_h_box(p, 2 * (p - sum_cnt_box[box]) + 1 + sum_cnt_box[box]);
p = 2 * (p - sum_cnt_box[box]) + 1 + sum_cnt_box[box];
}
else
break;
}
return h_box[l_box[box]];
}
int pop_card(int card)
{
l_card[card]--;
swap_h_card(sum_cnt_card[card], l_card[card]);
int p = sum_cnt_card[card];
for (;;)
{
if (2 * (p - sum_cnt_card[card]) + 2 + sum_cnt_card[card] < l_card[card])
{
if (comp_h_card(2 * (p - sum_cnt_card[card]) + 1 + sum_cnt_card[card], 2 * (p - sum_cnt_card[card]) + 2 + sum_cnt_card[card]) > 0)
{
if (comp_h_card(p, 2 * (p - sum_cnt_card[card]) + 2 + sum_cnt_card[card]) > 0)
swap_h_card(p, 2 * (p - sum_cnt_card[card]) + 2 + sum_cnt_card[card]);
p = 2 * (p - sum_cnt_card[card]) + 2 + sum_cnt_card[card];
}
else
{
if (comp_h_card(p, 2 * (p - sum_cnt_card[card]) + 1 + sum_cnt_card[card]) > 0)
swap_h_card(p, 2 * (p - sum_cnt_card[card]) + 1 + sum_cnt_card[card]);
p = 2 * (p - sum_cnt_card[card]) + 1 + sum_cnt_card[card];
}
}
else if (2 * (p - sum_cnt_card[card]) + 1 + sum_cnt_card[card] < l_card[card])
{
if (comp_h_card(p, 2 * (p - sum_cnt_card[card]) + 1 + sum_cnt_card[card]) > 0)
swap_h_card(p, 2 * (p - sum_cnt_card[card]) + 1 + sum_cnt_card[card]);
p = 2 * (p - sum_cnt_card[card]) + 1 + sum_cnt_card[card];
}
else
break;
}
return h_card[l_card[card]];
}
int T[200005], I[200005], J[200005];
int hoge[200005], fuga;
int main()
{
int n, q;
scanf("%d%d", &n, &q);
int i, j, k;
for (k = 0; k < q; k++)
{
scanf("%d %d", &T[k], &I[k]);
I[k]--;
if (T[k] == 1)
{
scanf("%d", &J[k]);
J[k]--;
}
}
for (i = 0; i < n; i++)
cnt_box[i] = 0;
for (k = 0; k < q; k++)
if (T[k] == 1)
cnt_box[J[k]]++;
sum_cnt_box[0] = 0;
for (i = 0; i < n; i++)
sum_cnt_box[i + 1] = sum_cnt_box[i] + cnt_box[i];
for (i = 0; i < 200005; i++)
cnt_card[i] = 0;
for (k = 0; k < q; k++)
if (T[k] == 1)
cnt_card[I[k]]++;
sum_cnt_card[0] = 0;
for (i = 0; i < 400000; i++)
sum_cnt_card[i + 1] = sum_cnt_card[i] + cnt_card[i];
for (i = 0; i < n; i++)
l_box[i] = sum_cnt_box[i];
for (i = 0; i < 200005; i++)
l_card[i] = sum_cnt_card[i];
for (k = 0; k < q; k++)
{
if (T[k] == 1)
{
push_box(J[k], I[k]);
push_card(I[k], J[k]);
}
else if (T[k] == 2)
{
fuga = 0;
while (l_box[I[k]] > sum_cnt_box[I[k]])
{
hoge[fuga] = pop_box(I[k]);
fuga++;
}
for (i = 0; i < fuga - 1; i++)
printf("%d ", hoge[i] + 1);
printf("%d\n", hoge[fuga - 1] + 1);
for (i = 0; i < fuga; i++)
push_box(I[k], hoge[i]);
}
else
{
fuga = 0;
while (l_card[I[k]] > sum_cnt_card[I[k]])
{
hoge[fuga] = pop_card(I[k]);
fuga++;
}
printf("%d", hoge[0] + 1);
for (i = 1; i < fuga; i++)
{
if (hoge[i] == hoge[i - 1])
continue;
printf(" %d", hoge[i] + 1);
}
printf("\n");
push_card(I[k], hoge[0]);
for (i = 1; i < fuga; i++)
{
if (hoge[i] == hoge[i - 1])
continue;
push_card(I[k], hoge[i]);
}
}
}
return 0;
}
一个错解:
By daisybunny
#include<bits/stdc++.h>
using namespace std;
int n,q;
vector<int> v[200005];
vector<int> v2[200005];
int main()
{
cin>>n>>q;
while(q--)
{
int x,i,j;
cin>>x>>i;
if(x==1)
{
cin>>j;
j--;
v2[i].push_back(j);
v[j].push_back(i);
}
else if(x==2)
{
i--;
sort(v[i].begin(),v[i].end());
for(int t=0;t<v[i].size();t++)
{
cout<<v[i][t]<<" ";
}
cout<<endl;
}
else
{
sort(v2[i].begin(),v2[i].end());
cout<<v2[i][0]+1<<" ";
for(int t=1;t<v2[i].size();t++)
{
if(v2[i][t]!=v2[i][t-1])
{
cout<<v2[i][t]+1<<" ";
}
}
cout<<endl;
}
}
return 0;
}
这个做法也是每次排序去重输出,但他并没有真的去重,导致集合里可能会有非常多重复元素,每次都要扫一遍但不输出。然而,题目只规定了输出的大小之和,并没有规定集合的元素个数和,而此时后者可能会比前者大得多,于是会超时。
Hack:
200000 200000
1 1 1
1 1 1
...
1 1 1 (100000 times)
3 1
3 1
...
3 1 (100000 times)