Algo_LeetCode_图论,根据数据规模设计算法

catalog


link

给定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;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值