贪心好题(题解)

1.E - MST + 1 (atcoder.jp)

        一.题意

                给定你一些边,和一些询问,问你在这个询问中新加入的这条边能否成为新最小生成树的边。

        二.解题思路

                直接按边权排序,若碰到新插入的和原来插入的边,则新插入的放在后边。

        三.代码实现

#include "bits/stdc++.h"
using namespace std;
const int N = 5e5 + 10;
struct Edge {int a,b,c,d;} e[N];
int f[N],ans[N];
int find(int x)
{
    return x == f[x] ? x : f[x] = find(f[x]);
}
void solve()
{
    int n,m,k;
    cin >> n >> m >> k;
    int idx = 0;
    for(int i = 1;i <= m;i++) {
        int a,b,c;
        cin >> a >> b >> c;
        e[++idx] = {a,b,c,0};
    }
    for(int i = 1;i <= k;i++) {
        int a,b,c;
        cin >> a >> b >> c;
        e[++idx] = {a,b,c,i};
    }
    sort(e + 1,e + 1 + idx,[](Edge &e,Edge &p){
        if(e.c < p.c) return true;
        if(e.c == p.c) return e.d < p.d;
        return false;
    });
    for(int i = 1;i <= n;i++) f[i] = i;
    int cnt = 0;
    for(int i = 1;i <= idx;i++) {
        if(cnt == n - 1) break;
        int a = e[i].a,b = e[i].b,c = e[i].c,d = e[i].d;
        int fa = find(a),fb = find(b);
        if(fa != fb) {
            if(d) {
                ans[d] = 1;
                continue;
            }
            f[fa] = fb;
            cnt ++;
        }
    }
    for(int i = 1;i <= k;i++) {
        if(ans[i]) cout << "Yes" << endl;
        else cout << "No" << endl;
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int T;
    T = 1;
    while(T --) {
        solve();
    }
    return 0;
}

2.F - Dist Max 2 (atcoder.jp)        

        一.题意

                给定你一些点对,每两对点对的价值为min(abs(x1 - x2),abs(y1 - y2),现在要求我们求这些点对中价值最大的点对的价值是多少?

        

        二.解题思路

                先按x排序,然后二分答案,对于每一个二分的值,我们需要找到任意一个x2 - x1 >= mid,并且abs(y2 - y1)>= mid,因此我们可以预处理后缀的最大和最小的y值。

        三.代码实现 

#include "bits/stdc++.h"
#define PII pair<int,int>
#define fi first
#define se second
using namespace std;
const int N = 2e5 + 10,inf = 0x3f3f3f3f;
int miy[N],mxy[N];
PII a[N];
int n;
bool check(int mid)
{
    for(int i = 1;i <= n;i++) {
        int idx = lower_bound(a + 1,a + 1 + n,make_pair(a[i].fi + mid,-inf)) - a;
        if(a[idx].fi - a[i].fi < mid) return false;
        int p1 = abs(mxy[idx] - a[i].se),p2 = abs(miy[idx] - a[i].se);
        if(max(p1,p2) >= mid) return true;
    }
    return false;
}
void solve()
{
    cin >> n;
    for(int i = 1;i <= n;i++) cin >> a[i].fi >> a[i].se;
    sort(a + 1,a + 1 + n);
    memset(mxy,-0x3f,sizeof(mxy));
    memset(miy,0x3f,sizeof(miy));
    int l = 0,r = a[n].fi - a[1].fi;
    for(int i = n;i >= 1;i--) {
        mxy[i] = max(a[i].se,mxy[i + 1]);
        miy[i] = min(a[i].se,miy[i + 1]);
    }
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(check(mid)) l = mid + 1;
        else r = mid - 1;
    }
    cout << max(0,l - 1) << endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int T;
    T = 1;
    while(T --) {
        solve();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值