這周學了啟發式合併,prim演算法,對圖有了進一步的理解。
樹
題意:給一棵根為 1 的有根樹,點 i 具有一個權值 \(A_i\)定義一個點對的值 f(u,v)=max(\(A_u\),\(A_v\))×∣\(A_u\)-\(A_v\)∣ 。你需要對於每個節點 i ,計算 \(ans_i=\displaystyle\sum_{u,v∈subtree(i)}f(u,v)\) ,其中 subtree(i) 表示 i 的子樹。請你輸出 ⊕($ans_i\ mod\ 2^{64}) $ ,其中 ⊕ 表示 XOR。
思路:樹上啟發式合併+線段樹
程式碼
#include <bits/stdc++.h>
#define int unsigned long long
#define ll unsigned long long
#define mod 1000000007
#define PII pair<int,int>
#define PIII pair<PII,int>
#define double long double
#define endl '\n'
#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
const int N = 1e6 + 5, SZ = N << 2;
ll a[N];
int c[N], vis[N];
vector<int>g[N];
int dp[N][2];
int s1, s2;
int mn =0, mx, sum, ss2;
int n, k, m;
set<PII>qqq;
int qpow(int x, int y) {
int ans = 1;
while (y) {
if (y & 1)ans = (ans * x) % mod;
x = (x * x) % mod;
y >>= 1;
}
return ans;
}
int pos[N];
struct data {
int tad,cnt;
ll sum,sum2;
ll max, min;
} t[N << 2];
void push_up(int u) {
t[u].cnt = (t[u << 1].cnt + t[u << 1 | 1].cnt);
t[u].sum = (t[u << 1].sum + t[u << 1 | 1].sum);
t[u].sum2 = (t[u << 1].sum2 + t[u << 1 | 1].sum2);
t[u].max = max(t[u << 1].max, t[u << 1 | 1].max);
t[u].min = min(t[u << 1].min, t[u << 1 | 1].min);
}
void build(int u = 1, int l = 1, int r = N) {
if (l == r) {
pos[l] = u;
t[u].cnt=c[l];
t[u].sum=l*c[l];
t[u].sum2=l*l*c[l];
t[u].max = l;
t[u].min = l;
return;
}
int mid = (l + r) >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
push_up(u);
}
void add(int p) {
int u = pos[p];
t[u].cnt++;
t[u].max = p;
t[u].min = p;
t[u].sum+=p;
t[u].sum2+=p*p;
while (u >>= 1)push_up(u);
}
void del(int p) {
int u = pos[p];
t[u].cnt--;
t[u].sum-=p;
t[u].sum2-=p*p;
if (!t[u].cnt) {
t[u].max = 0;
t[u].min=1e9;
}
while (u >>= 1)push_up(u);
}
ll qmax(int L, int R, int u = 1, int l = 1, int r = N) {
if (R < l || r < L) return 0;
if (L <= l && r <= R) return t[u].max;
int mid = (l + r) >> 1;
return max(qmax(L, R, u << 1, l, mid) , qmax(L, R, u << 1 | 1, mid + 1, r));
}
ll qsum(int L, int R, int u = 1, int l = 1, int r = N) {
if (R < l || r < L) return 0;
if (L <= l && r <= R) return t[u].sum;
int mid = (l + r) >> 1;
return (qsum(L, R, u << 1, l, mid) + qsum(L, R, u << 1 | 1, mid + 1, r));
}
ll qsum2(int L, int R, int u = 1, int l = 1, int r = N) {
if (R < l || r < L) return 0;
if (L <= l && r <= R) return t[u].sum2;
int mid = (l + r) >> 1;
return (qsum2(L, R, u << 1, l, mid) + qsum2(L, R, u << 1 | 1, mid + 1, r));
}
ll qcnt(int L, int R, int u = 1, int l = 1, int r = N) {
if (R < l || r < L) return 0;
if (L <= l && r <= R) return t[u].cnt;
int mid = (l + r) >> 1;
return (qcnt(L, R, u << 1, l, mid) + qcnt(L, R, u << 1 | 1, mid + 1, r));
}
ll qmin(int L, int R, int u = 1, int l = 1, int r = N) {
if (R < l || r < L) return 1e9;
if (L <= l && r <= R) return t[u].min;
int mid = (l + r) >> 1;
return min(qmin(L, R, u << 1, l, mid) , qmin(L, R, u << 1 | 1, mid + 1, r));
}
int sz[N], big[N], L[N], R[N], Node[N], totdfn;
int cnt[N], totColor;
ll ans[N];
void dfs0(int u, int p) {
L[u] = ++totdfn;
Node[totdfn] = u;
sz[u] = 1;
for (int v : g[u])
if (v != p) {
dfs0(v, u);
sz[u] += sz[v];
if (!big[u] || sz[big[u]] < sz[v]) big[u] = v;
}
R[u] = totdfn;
}
void dfs1(int u, int p, bool keep) {
for (int v : g[u])
if (v != p && v != big[u]) {
dfs1(v, u, false);
}
if (big[u]) {
dfs1(big[u], u, true);
}
for (int v : g[u])
if (v != p && v != big[u]) {
for (int i = L[v]; i <= R[v]; i++) {
ans[u]+=2*qcnt(1,a[Node[i]])*a[Node[i]]*a[Node[i]];
// cout<<qcnt(1,a[Node[i]])*a[Node[i]]*a[Node[i]]<<endl;
ans[u]+=2*qsum2(a[Node[i]]+1,N);
// cout<<qsum2(a[Node[i]]+1,N)<<endl;
ans[u]-=2*qsum(1,N)*a[Node[i]];
// cout<<qsum(1,N)*a[Node[i]]<<endl;
add(a[Node[i]]);
// cout<<a[Node[i]]<<endl;
// for (int l = 1; l <= 10; l++) {
// cout<<qsum(l,l)<<" \n"[l==10];
// }
}
}
ans[u]+=2*qcnt(1,a[u])*a[u]*a[u];
// cout<<qcnt(1,a[u])*a[u]*a[u]<<endl;
ans[u]+=2*qsum2(a[u]+1,N);
// cout<<qsum2(a[u]+1,N)<<endl;
ans[u]-=2*qsum(1,N)*a[u];
// cout<<qsum(1,N)*a[u]<<endl;
add(a[u]);
// cout<<"ans"<<u<<' '<<ans[u]<<endl;
// cout<<a[u]<<endl;
// for (int i = 1; i <= 10; i++) {
// cout<<qsum(i,i)<<" \n"[i==10];
// }
if (keep == false) {
for (int i = L[u]; i <= R[u]; i++) {
del(a[Node[i]]);
}
}else{
ans[p]+=ans[u];
}
}
void solve() {
int s;
cin >> n ;
for (int i = 1; i < n; i++) {
int u, v, x;
cin >> u >> v;
g[u].emplace_back(v);
g[v].emplace_back(u);
}
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
// for (int i = 1; i <= 10; i++) {
// cout<<qcnt(i,i)<<" \n"[i==10];
// }
build();
dfs0(1, 0);
dfs1(1, 0, false);
ll Ans=0;
for (int i = 1; i <= n; i++) {
Ans^=ans[i];
// cout<<ans[i]<<" \n"[i==n];
}
cout<<Ans<<endl;
}
int32_t main() {
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T = 1;
//cin >> T;
while (T--) {
solve();
}
return 0;
}
MST公司
題意:你面對的是一個加權無向圖,它包含n頂點 和m沒有任何自環的邊緣。Sajin 呈現q查詢。對於每個頂點集S是給出的。您的目標是確定S並找到其最小生成樹的權重。最小生成樹 (MST) 是連線的邊加權圖的邊的子集,它以儘可能小的總邊權重將所有頂點連線在一起,無需任何迴圈。在圖論的數學領域中,圖的誘導子圖是另一個圖,由圖的頂點子集和原始圖中的所有邊組成,連線該子集中的頂點對。如果誘導子圖S已斷開連線,輸出 -1。
思路:根號分治+prim演算法
程式碼
#include <bits/stdc++.h>
#define ll long long
//#define int long long
#define mod 1000000007
#define PII pair<int,ll>
#define PIII pair<PII,int>
#define double long double
#define endl '\n'
#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
const int N = 1e5 + 5, SZ = N << 2;
int k;
int n, m, h[N], cnte;
int a[N], b[N];
vector<PII>g[N], G[N];
struct S {
int u;
ll d;
};
bool operator<(const S &x, const S &y) {
return x.d > y.d;
}
priority_queue<S> q;
ll dis[N];
bool vis[N];
ll res = 0, cnt = 0;
void Prim(int x) {
res = 0, cnt = 0;
for (int i = 0; i < k; i++) {
dis[b[i]] = 1e18;
vis[b[i]] = 0;
}
dis[x] = 0;
while (q.size())q.pop();
q.push({x, 0});
while (!q.empty()) {
if (cnt >= n) break;
int u = q.top().u, d = q.top().d;
// cout << u << ' ' << d << endl;
q.pop();
if (vis[u]) continue;
vis[u] = 1;
++cnt;
res += d;
for (auto[v,w] : g[u]) {
// cout << v << ' ' << w << 'x' << endl;
if (w < dis[v] && a[v]) {
dis[v] = w, q.push({v, w});
}
}
}
}
void Prim1(int x) {
res = 0, cnt = 0;
for (int i = 0; i < k; i++) {
dis[b[i]] = 1e18;
// cout<<' '<<b[i]<<endl;
vis[b[i]] = 0;
}
dis[x] = 0;
while (q.size())q.pop();
q.push({x, 0});
while (!q.empty()) {
if (cnt >= n) break;
int u = q.top().u, d = q.top().d;
q.pop();
if (vis[u]) continue;
vis[u] = 1;
++cnt;
res += d;
// cout << u << ' ' << d <<' '//<<res<< endl;
for (auto[v, w] : G[u]) {
// cout << v << ' ' << w << 'y' << endl;
// cout<< dis[v] <<' '<<a[v]<<endl;
if (w < dis[v] && a[v]) {
// cout<<'t'<<endl;
dis[v] = w, q.push({v, w});
}
}
}
}
void solve() {
int q;
cin >> n >> m >> q;
for (int i = 1; i <= m; i++) {
int u, v, x;
cin >> u >> v >> x;
g[u].push_back({v,x});
g[v].push_back({u,x});
}
for(int i=1;i<=n;i++){
sort(g[i].begin(),g[i].end());
}
int nn = 3e2;
for (int i = 0; i < q; i++) {
cin >> k;
for (int j = 0; j < k; j++) {
int x;
cin >> x;
a[x] = 1;
b[j] = x;
}
if (k < nn) {
for (int j = 0; j < k; j++) {
for (int l = 0; l < k; l++) {
if(j==l)continue;
PII op={b[l],0};
int pp=lower_bound(g[b[j]].begin(),g[b[j]].end(),op)-g[b[j]].begin();;
if(pp<g[b[j]].size()&&a[g[b[j]][pp].first]){
//cout<<g[b[j]][pp].first<<' '<<g[b[j]][pp].second<<endl;
G[b[j]].push_back(g[b[j]][pp]);
}
}
}
}
if (k < nn) {
Prim1(b[0]);
for (int i = 0; i < k; i++) {
G[b[i]].clear();
}
} else {
Prim(b[0]);
}
for (int j = 0; j < k; j++) {
a[b[j]]=0;
}
if (cnt == k)cout << res << endl;
else cout << -1 << endl;
// cout << endl;
}
}
int32_t main() {
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T = 1;
//cin >> T;
while (T--) {
solve();
}
return 0;
}