英文题干
There are n people standing in a line, numbered from 1 to n from left to right. Among these people, there are m pairs of friends.
Define an interval as friendly if and only if every pair of people within the interval are friends.
How many friendly intervals are there?
Input:
The first line contains two integers and
(
), representing the number of people and the number of pairs of friends, respectively.
The next lines each contain two integers
and
(
), representing a pair of friends.
It is guaranteed that there are no duplicate friend pairs in the input.
Output:
Output a single integer representing the number of friendly intervals.
中文题干
有n个人站在一条线上,从左到右编号为1到n。在这些人中,有m对朋友。
定义一个区间为友好区间,当且仅当该区间内的每对人都是朋友时。
有多少个友好区间?(注:此处朋友不具有传递性,且长度为1的区间也是友好区间)
思路
-
我们考虑按照类似求前缀和的方式求区间总数,首先记录2到n每个序号的人能向前扩展到的最小序号的人(如果中间断了就说明不能继续扩展了,因为不具有传递性)
-
然后按从小到大的顺序依次合并,计算区间个数。i 能贡献的区间数就是
, 并且更新 i 能向前扩展到的最小序号为
(走不了回头路,前面断了的后面不可能再成为友好区间)。最后加上长度1的区间即可。
AC代码
时间复杂度:O()
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int infmin = 0xc0c0c0c0;
const int infmax = 0x3f3f3f3f;
const int maxn = 1e6 + 10;
int n, m;
ll ans = 0;
vector<int> mp[maxn];
int expand[maxn]; // 以 i 结尾的最长友好区间的左端点
inline bool cmp(int x, int y) {
return x > y;
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
int fr1, fr2;
for (int i = 1; i <= m; i++) {
cin >> fr1 >> fr2;
if (fr1 < fr2)
swap(fr1, fr2);
mp[fr1].push_back(fr2); // 把较小的那个编号存入较大的编号对应的朋友列表中
}
for (int i = 2; i <= n; i++) {
sort(mp[i].begin(), mp[i].end(), cmp);
int faridx = i; // 记录区间能扩展到的最远位置(序号最小的人)
for (int j = 0; j < mp[i].size(); j++) {
if (mp[i][j] == faridx - 1) {
faridx--;
expand[i] = faridx;
}
else {
break;
}
}
}
// 处理长度为1的区间
for (int i = 1; i <= n; i++) {
if (expand[i] == 0) {
expand[i] = i;
}
}
// 计算友好区间数量
for (int i = 2; i <= n; i++) {
ans += min(i - expand[i], i - expand[i - 1]);
expand[i] = max(expand[i], expand[i - 1]);
}
cout << ans + n << endl; // 加上长度为1的区间
return 0;
}
// Inspired by LJY