给定n=1e5个点的无向图(不一定联通),其中有m=1e5条边(有重边)
有query=20个查询,每次一个val表示:
有多少个V(x, y)的值是 > val的 (其中,x和y表示pair,且x != y)
V(x,y) = x的出度 + y的出度 - (x和y的直通边).
伪代码:
while(query -- ){
cin >> val;
FOR(i, 1, n, 1){
FOR(j, 1, n, 1){
if(i == j) continue;
if(din[i] + din[j] - connect[i][j] > val) ++ ans;
}
}
cout << ans;
}
1,query很小=20 这一信息,一定要抓住!!!
说明,肯定不是'预处理',应该是 每次query,都去O(n)的遍历
2,找给定的val,有多少个pair满足: (din[i] + din[j] > val)
FOR(i, 1, n, 1){
int need = val + 1 - din[i];
二分找,有多少个din是 >= need的 (注意,可能需要减去 i)
}
3,此时是重点!!! 你现在得到了很多的j,有(din[i] + din[j] > val)
但是,可能 (din[i] + din[j] - conn[i][j] <= val),你需要 再减去 非法的j
但,直接去遍历j 肯定是超时的。
'此时,这是 图论问题,经常会考察大家的点!!!'
'即,看似是只有O(1)能够解决的问题 {这个问题,确确实实是 O(n)遍历才能解决的!!!}'
'但是,由于 m边数 = 1e5,只有1e5条边!! '
'即,这个问题 确实是O(n * n)的算法; 但由于m不是极限,所以 可以优化成O(n + m)的算法!!'
即,我们每次 遍历 每个点的 所有的临界点 '
VE<int> din(n + 4, 0);
UMAP<int,int> mp[n + 1]; '重点!!! m=1e5个无向边,你的map 只有2e5个数据!!!'
for(auto& i : A){
din[i[0]] ++, din[i[1]] ++;
mp[i[0]][i[1]] ++, mp[i[1]][i[0]] ++;
}
VE<int> bac(n);
FOR(i, 1, n, 1){ bac[i - 1] = din[i]; }
sort(bac.begin(), bac.end());
VE<int> ans;
for(int q : Q){
int anss = 0;
FOR(i, 1, n, 1){
int cur = din[i];
int need = q + 1 - cur;
auto it = lower_bound( VE_ALL(bac), need);
int add = bac.end() - it; '对答案的贡献'
if(cur >= need) add --; '说明,add里 包含了 i当前点本身, 需要去掉'
for(auto& [j, w] : mp[i]){ '重点!!! 因为m边数 很少 '
if(din[j] >= need){
if(din[j] + din[i] - w <= q){ -- add; }
}
}
anss += add;
}
ans.PB(anss >> 1);
}
return ans;
Algo_LeetCode_图论,根据数据规模设计算法
于 2021-03-15 22:12:58 首次发布