E. Spanning Tree Queries(最小生成树,贪心)
来源场次
Educational Codeforces Round 122 (Rated for Div. 2)
Tag
最小生成树,暴力,*2400
题目大意
给一张图,图中有\(n\)个结点\(m\)条边,每条边的权值为\(w\),有\(k\)次询问,每次询问给定一个数值\(x\),对于每一次的\(x\),图中所有边的权值更改为\(\left|w_i-x\right|\),求每次询问的最小生成树的权值
思路
- 由于题目中的k非常大,不可能每次都去暴力求解一遍最小生成树,因此可以考虑预处理一些关键的最小生成树的值
- 我们知道对于任意的两条边, \(w_i\)和\(w_j\)\((i \neq j)\),当x为它们两个的中点时,这两条边在所有边的排序中将会交换位置,所得到的生成树的值也最有可能会发生改变。因此,我们可以预处理出当\(x\)为任意两条边的中点时的生成树的值
- 现在的问题是,如果\(x\)的值不在我们认为的理想的点,那我们可以顺带统计,在理想点时位于x左边和位于x右边的值分别有多少个,在\(x\)发生偏移时,我们就可以对这段偏移值的影响估算进去。
AC代码
#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0)
#define LL long long
#define maxn (int)(1e6 + 10)
int n , m;
LL w[550] , u[550] , v[550];
int p[550] , r[550];
int find ( int x ) { return p[x] == x ? x : p[x] = find(p[x]) ;}
pair<LL,int> Kruskal (LL xx) {
LL ans = 0;
for ( int i = 1 ; i <= n ; i++ ) p[i] = i;
for ( int i = 1 ; i <= m ; i++ ) r[i] = i;
sort ( r+1 , r+m+1 , [xx](const int i, const int j){
LL wa = abs(w[i]-xx);
LL wb = abs(w[j]-xx);
if ( wa != wb ) return wa < wb;
return w[i] > w[j]; // 由于x往右偏移的时候对右边的值更友好,所以相等时右边的值理应更优先
});
int cc = 0;
for ( int i = 1 ; i <= m ; i++ ) {
int e = r[i] ; int x = find(u[e]) ; int y = find(v[e]);
if ( x != y ) {
ans += abs(w[e]-xx) ; p[x] = y ;
cc += xx < w[e];
}
}
return {ans,cc};
}
vector<LL> res;
vector<int> cnt;
LL P , k , a , b , c;
int main ()
{
IOS;
cin >> n >> m ;
for ( int i = 1 ; i <= m ; i++ )
{
cin >> u[i] >> v[i] >> w[i];
w[i] *= 2;
}
vector<LL> ev(1,0);
for ( int i = 1 ; i <= m ; i++ )
for ( int j = i ; j <= m ; j++ )
ev.push_back(w[i]+w[j] >> 1);
sort(ev.begin(), ev.end());
ev.resize(unique(ev.begin(), ev.end()) - ev.begin());
for ( auto xx : ev )
{
auto ss = Kruskal(xx);
res.push_back(ss.first);
cnt.push_back(ss.second);
}
LL ans = 0 ;
cin >> P >> k >> a >> b >> c;
LL x;
for ( LL cas = 1 ; cas <= k ; cas++ )
{
if ( cas <= P )
cin >> x;
else
x = (x * a + b) % c;
int pos = upper_bound(ev.begin(), ev.end(), 2*x) - ev.begin() - 1;
ans ^= ( res[pos] + (n-1-2*cnt[pos]) * 1ll * (2*x - ev[pos])) / 2;
// 加上左右两边点的个数的差值
}
// for ( auto xx : cnt )
// cout << xx << " ";
// cout << endl;
cout << ans << endl;
}
浙公网安备 33010602011771号