题目链接
给定一个长度为 n 的序列 a ,一共有 m 个操作。
每次操作的内容为:给定 x,y ,序列中所有 x 会变成 y 。
同时我们有一份代码:
int ans = 2147483647;
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
if (a[i] == a[j])
ans = std::min(ans, j - i);
}
}
std::cout << ans << std::endl;
请在每次修改后输出代码运行的结果。
第一行两个数,表示 n,m 。
第二行 n 个数,表示 a1,a2,⋯,an 。
然后 m 行每行两个数 x 和 y ,表示序列中所有 x 会变成 y 。
对于每次修改,输出答案。
5 10
2 7 6 3 8
6 1
7 1
1 3
5 6
1 7
9 5
1 10
7 6
7 5
3 9
2147483647
1
1
1
1
1
1
1
1
1
1≤n,m≤100000
每个出现的数字绝对值在 int 范围内。
给出操作,将序列中所有一个数字替换为另一个,询问每次操作后距离最近的两个相同数字的距离。
每个数字只与他的前驱和后继产生贡献。构建 n 个set,每次将较小的暴力合并到大的上面,通过lower_bound来找到他的前驱和后继。懒得离散化可以用map来存set。
#include
using namespace std;
map< int, set<int> > a;
int n, m, ans = INT_MAX;
void update(int x, int y){
set<int>::iterator it;
it = a[x].lower_bound(y);
if(it != a[x].end()) ans = min(ans, *it - y);
if(it != a[x].begin()) it--, ans = min(ans, y - *it);
}
void init(){
scanf("%d%d", &n, &m);
for(int i = 1, x; i <= n; i++){
scanf("%d", &x);
update(x, i);
a[x].insert(i);
}
}
void work(){
for(int i = 1, x1, x2; i <= m; i++){
scanf("%d%d", &x1, &x2);
if(x1 == x2){
printf("%d\n", ans);
continue;
}
if(a[x1].size() > a[x2].size()) swap(a[x1], a[x2]);
for(set<int>::iterator it = a[x1].begin(); it != a[x1].end(); it++){
update(x2, *it);
a[x2].insert(*it);
}
a[x1].clear();
printf("%d\n", ans);
}
}
int main(){
init();
work();
return 0;
}