HDU 6763(2020 Multi-University Training Contest 2-A)--贪心,并查集,思维

打比赛时脑子落家了,没A出来,补题过的…

(另外题目在比赛时有修改,这里只说修改后的)
题意:给你一个图(N,E),n个点,m条双向边,每个点有一个值b[i],
你可以操作任意以下操作:
选择一个点,并将当前情况下从该点到达的所有点(包括该点),的值b都减1.
注意:当某个点的值b变成0时,这个点将不会进入后面的运算,相当于此时刻后该点与连此点的边都会消失.

问:你至少操作多少次才能将所有的值都减小为0.

思路:对b数组按照从大到小排序,for一遍将点v添加到图中,对每个点,先判断该点连接的互相不联通的图的个数c,则ans+=(v点的值bv)*(1-c)
跑完后ans就是结果了,

实现:判断是否联通用并查集维护就好了,

注意:结果会暴int,用long long存储,中间数也可能暴int,乘之前先转化成long long.
先查再并,否则可能会多算一个.

证明:其实我不会…
当图中加入一个新的点v时,原本没有联通的两(多)个子图将会联通,此时图中的任意一个点的值b都比加入的点的值b[v]大(或者等于),
那么
对任意一个与v有边的子图来说
进行b[v]次下述操作
{
{将原本对子图中某个点的操作}
转移到v
}
不会对原本的图有任何影响(当操作b[v]此后v与原来的子图分割).
这样会转移bvc次,只需要将操作次数提升bv(c-1)次数(甚至会减少).

为什么这样就是最优呢?
其实我不会…

//#pragma comment(linker, "/STACK:102400000,102400000")
//#pragma optimize("-O3")
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
#ifdef Wang_Zhifeng

void debug_out() { cout << '\n'; }

template<typename T, typename... R>
void debug_out(const T &f, const R &... r) {
    cout << f << " ";
    debug_out(r...);
}
//#define debug(x) printf("debug:%s=%d\n",#x,x);
#define debug(...) cout << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__);
#endif

#define ll long long
#define MAXN 100005

int n, m;
ll ans;
int add2;
struct node {
    int val;
    int pos;
} b[MAXN];
vector<vector<int>> edge(MAXN);
int need[MAXN];
bool vis[MAXN];

bool cmp(node a, node b) {
    return a.val > b.val;
}

class and_collect {
public:
    int parent[MAXN];
    int rank[MAXN];

    ///初始化
    void init() {
        for(int i = 0; i < MAXN; ++i) {
            parent[i] = i;
            rank[i] = 0;
        }
    };

    ///在查询的过程中实现了路径压缩
    int find(int a) {
        if(parent[a]==a) {
            return a;
        } else {
            return parent[a] = find(parent[a]);
        }
    }

    ///在合并的过程中实现按照rank合并
    void bing(int a, int b) {
        a = find(a);
        b = find(b);
        if(a==b)
            ///可以根据需要将 将函数改写成带有查功能的函数
            return;
        if(rank[a] < rank[b])
            parent[a] = b;
        else {
            parent[b] = a;
            if(rank[a]==rank[b])
                ++rank[a];
        }
    }

    bool cha(int a, int b) {
        return find(a)==find(b);
    }
};

and_collect andCollect;

void init() {
    andCollect.init();
    ans = 0;
    for(int i = 0; i <= n; ++i) {
        edge[i].clear();
        vis[i] = false;
        need[i] = 0;
    }
}

void input() {
    int ta, tb;
    scanf("%d%d", &n, &m);
    init();
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &b[i].val);
        b[i].pos = i;
    }
    while(m--) {
        scanf("%d%d", &ta, &tb);
        if(b[ta].val==b[tb].val) {
            edge[ta].push_back(tb);
            edge[tb].push_back(ta);
        } else if(b[ta].val < b[tb].val) {
            edge[ta].push_back(tb);
        } else {
            edge[tb].push_back(ta);
        }
    }
    sort(b+1, b+1+n, cmp);
}

void solve() {
    int t;
    int tmp;
    int len;
    scanf("%d", &t);
    while(t--) {
        input();

        for(int i = 1; i <= n; ++i) {
            map<int, bool> mp;
            add2 = 0;
            len = edge[b[i].pos].size();
//            debug(i)
//            debug(b[i].pos, b[i].val)
            for(int j = 0; j < len; ++j) {
                if(!vis[edge[b[i].pos][j]])continue;
                tmp = andCollect.find(edge[b[i].pos][j]);
                if(!mp[tmp]) {
                    add2++;
                    mp[tmp] = true;
                }
            }
            for(int j = 0; j < len; ++j) {
                andCollect.bing(b[i].pos, edge[b[i].pos][j]);
            }
            need[andCollect.find(b[i].pos)] = b[i].val;
            ans += 1ll*b[i].val*(1-add2);
            vis[b[i].pos] = true;
        }
        printf("%lld\n", ans);
    }
}


int main() {
#ifdef Wang_Zhifeng
    freopen("in.txt", "r", stdin);
    setvbuf(stdout, NULL, _IOFBF, 1024);
    clock_t startTime, endTime;
    startTime = clock();
    //std::ios::sync_with_stdio(false);
    //cin.tie(0);
#endif

    solve();

#ifdef Wang_Zhifeng
    endTime = clock();
    cout << "time: " << (float) (endTime-startTime)*1000/CLOCKS_PER_SEC << " ms" << endl;
#endif
    return 0;
}

你可能感兴趣的:(HDU 6763(2020 Multi-University Training Contest 2-A)--贪心,并查集,思维)