灵魂滚烫, 命运冰凉|

fhq_treap

园龄:5年7个月粉丝:67关注:21

ZR省选十连测

#1

A

考虑其等价于把0看作<,1看作>求满足条件的排列数量。

可以使用容斥加分治FFT解决其。

B

太难了,补不动。

C

考虑gi,j,j[0,3] 为通过i往上延伸的j长度的链的子树内部权值。

这里只考虑k=4 的情况。

思考我们需要记录前缀合并情况里s1>s3 的个数,以及s2 的寄偶性。

如果随机序列1,1 其前缀和大概率不大于n,我们随机打碎儿子,然后记录即可。

点击查看代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
using namespace std;

typedef pair <int, int> pii;

const long long INF = 0x3f3f3f3f3f3f3f3f;

long long dp[200010][5];
vector <pii> G[200010];
int n, k;
long long f[2010][2];

void dfs(int x, int last) {
	int son = 0;
	for (auto it : G[x]) {
		int v = it.fi, w = it.se;
		if (v == last) continue;
		dfs(v, x), son++;
	}
	int S = min(2001, son << 1 | 1);
	for (int i = 0; i <= S; i++) {
		f[i][0] = f[i][1] = -INF;
	}
	random_shuffle(G[x].begin(), G[x].end());
	int be = S >> 1;
	f[be][0] = 0;
	for (auto it : G[x]) {
		int v = it.fi, w = it.se;
		if (v == last) continue;
		long long lst[2] = {-INF, -INF};
		for (int i = 0; i < S; i++) {
			long long cur[2] = {f[i][0], f[i][1]};
			for (int j = 0; j < 2; j++) {
				f[i][j] += max(dp[v][0], dp[v][k - 1] + w);
				f[i][j] = max(f[i][j], lst[j] + dp[v][0] + w);
				f[i][j] = max(f[i][j], f[i + 1][j] + dp[v][k - 2] + w);
				if (k == 4) f[i][j] = max(f[i][j], cur[j ^ 1] + dp[v][1] + w);
			}
			lst[0] = cur[0], lst[1] = cur[1];
		}
	}
	dp[x][0] = f[be][0];
	dp[x][1] = f[be + 1][0];
	dp[x][k - 1] = be ? f[be - 1][0] : -INF;
	if (k == 4) dp[x][2] = f[be][1];
}

int main() {
	srand((int)time(NULL));
	scanf("%d%d", &n, &k);
	for (int i = 1; i < n; i++) {
		int x, y, w; scanf("%d%d%d", &x, &y, &w);
		G[x].push_back(mp(y, w));
		G[y].push_back(mp(x, w));
	}
	dfs(1, 1);
	printf("%lld\n", dp[1][0]);
	return 0;
}

#4

A

一个诈骗题,考虑对每个点向外BFS寻找非平凡回路,只要uv时,v在之前遇到过,则该点的答案为disv

点击查看代码
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
const int Maxn=5000;
const int Inf=0x3f3f3f3f;
int n;
std::vector<int> g[Maxn+5];
int dis[Maxn+5];
bool vis[Maxn+5];
int qu[Maxn+5],qu_f,qu_t;
int init_bfs(int S){
	memset(dis,0x3f,sizeof dis);
	memset(vis,0,sizeof vis);
	dis[S]=0,vis[S]=1;
	qu_f=1,qu_t=0;
	qu[++qu_t]=S;
	while(qu_f<=qu_t){
		int u=qu[qu_f++];
		for(int v:g[u]){
			if(!vis[v]){
				dis[v]=dis[u]+1;
				vis[v]=1;
				qu[++qu_t]=v;
			}
			else if(dis[u]<=dis[v]){
				return dis[u]+1;
			}
		}
	}
	return -1;
}
int main(){
	scanf("%d",&n);
	for(int i=2;i<=n;i++){
		static char s[Maxn+5];
		scanf("%s",s+1);
		int len=0;
		while(s[++len]!='\0');
		len--;
		for(int j=1;j<i;j++){
			if(s[j]=='1'){
				g[i].push_back(j),g[j].push_back(i);
			}
		}
	}
	for(int i=1;i<=n;i++){
		printf("%d\n",init_bfs(i));
	}
	return 0;
}

B

image

#5

A

写做fi=(mex(j,i)fj1)

考虑我们只要每次每次后缀加入一个数动态维护mex即可,考虑我们每次加入后缀时,直接查询在mex=ai[l,r]里查询前缀mex的位置,并直接更新其前缀为mex<mex+1,考虑每次都把对应位置的mex变为大于其权值,一个数只会变一次,所以复杂度有所保证。

B

考虑有结论

结论一:当a<b<c,有ac>=min(ab,bc),那么即最小值异或对只会出现在相邻的i,j

结论二:当b>=a,aa>=ba,当有这两个结论时我们就可以做sub1,sub2,sub3

我们考虑当w>min(aiaj)时,可以构造出答案为min(aiaj),那么我们只要每次都枚举小于min(aiaj)x,记录其答案即可。

考虑实际上加入一个数时其mn递减,那么只要枚举时对新加入的对统计即可,那么复杂度为O(2Vi)=O(V2V)

点击查看代码

//晦暗的宇宙,我们找不到光,看不见尽头,但我们永远都不会被黑色打倒。——Quinn葵因
#include<bits/stdc++.h>
#define ll long long
#define N 1000005

using std::set;

set<int>A;

int V,n;

#define inf (1ll << 21)

int mn = inf;

ll ans[inf];

int main(){
	scanf("%d%d",&V,&n);
	for(int i = 0;i < inf;++i)
	ans[i] = inf;
	for(int i = 1;i <= n;++i){
		int opt,x;
		scanf("%d%d",&opt,&x);
		if(opt == 1){
			A.insert(x);
			set<int>::iterator it = A.lower_bound(x);
			set<int>::iterator cur = it;
			if(it != A.begin()){
				-- it;
//				std::cout<<"("<<*it<<" "<<x<<")"<<"\n"; 
				mn = std::min(mn,x - *it);
				for(int i = 0;i <= mn;++i)
				ans[i] = std::min(ans[i],1ll * (i + *it) ^ (i + x)),ans[i] = (i == 0) ? ans[i] : std::min(ans[i - 1],ans[i]);
			}
			it = ++cur;
			if(it != A.end()){
				mn = std::min(mn,*it - x);
//				std::cout<<"("<<x<<" "<<*it<<")"<<"\n"; 				
				for(int i = 0;i <= mn;++i)
				ans[i] = std::min(ans[i],1ll * (i + *it) ^ (i + x)),ans[i] = (i == 0) ? ans[i] : std::min(ans[i - 1],ans[i]);				
			} 
//			std::cout<<mn<<"\n";
		}else{
			if(x > mn)
			std::cout<<mn<<"\n";
			else
			std::cout<<ans[x]<<"\n"; 
		}
	}
}

结论三:考虑到答案的最终贡献方式,一定是让所有相邻对的某一位的后k位归0,即可贡献维护的答案x不超过Vn个,考虑直接对这Vn个维护即可。

点击查看代码
ans[i] = std::min(ans[i],1ll * (i + *it) ^ (i + x)),ans[i] = (i == 0) ? ans[i] : std::min(ans[i - 1],ans[i]);
			}
			it = ++cur;
			if(it != A.end()){
				mn = std::min(mn,*it - x);
//				std::cout<<"("<<x<<" "<<*it<<")"<<"\n"; 				
				for(int i = 0;i <= mn;++i)
				ans[i] = std::min(ans[i],1ll * (i + *it) ^ (i + x)),ans[i] = (i == 0) ? ans[i] : std::min(ans[i - 1],ans[i]);				
			} 
//			std::cout<<mn<<"\n";
		}else{
			if(x > mn)
			std::cout<<mn<<"\n";
			else
			std::cout<<ans[x]<<"\n"; 

C

考虑每次维护中间块[OL,OR]=k这一块的最小生成树,然后左边的在中间k个点虚树上的边,后缀维护,还有右边整块的前缀。

然后考虑删除时直接暴力重构。

#6

给我心态打崩了。
坐牢,签到都没签上。

A

怎么开局一直想着枚举左端点。
考虑强制钦定最小值的位置,设li为左边比hi的大的数,ri为在右边比他大的数。
x=li+ri+1
i=li+1
考虑其对于一个询问k的贡献实际上是
min(i,xi+1,k,xk+1)

考虑对于所有k都维护一个这样的贡献,那么其实际上可以通过拆成系数和常数分开维护。

(借一下rsx的代码)

#6 A
#include <bits/stdc++.h>
const int MAXN = 1e5 + 10;
using std::cin;
using std::cout;
template <typename T>
inline T min(const T &x, const T &y) {
	return x < y ? x : y;
}
template <typename T>
struct Fenwick_Tree {
	int limit;
	T t[MAXN];
	void add(int x, T y) {
		for (; x <= limit; x += x & -x) {
			t[x] += y;
		}
		return;
	}
	T sum(int x) {
		T ret = 0;
		for (; x; x -= x & -x) {
			ret += t[x];
		}
		return ret;
	}
	void build(int _N) {
		limit = _N;
	}
};
Fenwick_Tree <int> cyc;
int N, L, R, A[MAXN], Pos[MAXN];
long long K[MAXN], B[MAXN];
void add(long long *qjy, int l, int r, long long v) {
	qjy[l] += v;
	qjy[r + 1] -= v;
}
int main() {
	std::ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> N >> L >> R;
	for (int i = 1; i <= N; ++i) {
		cin >> A[i];
		Pos[A[i]] = i;
	}
	cyc.build(N);
	for (int i = 1; i <= N; ++i) {
		cyc.add(Pos[N - i + 1], 1);
		int Tk = cyc.sum(Pos[N - i + 1]);
		int Tmp = min(Tk, i - Tk + 1);
		add(K, 1, Tmp, 1);
		add(B, Tmp + 1, i - Tmp, Tmp);
		add(K, i - Tmp + 1, i, -1);
		add(B, i - Tmp + 1, i, i + 1);
	}
	for (int i = 1; i <= N; ++i) {
		K[i] += K[i - 1];
		B[i] += B[i - 1];
	}
	long long SUM = 0;
	for (int i = L; i <= R; ++i) {
		SUM ^= K[i] * i + B[i];
	}
	cout << SUM << '\n';
	return 0;
}

B

考虑对格子上的史莱姆进行dp,这样发现其可以发现史莱姆合并的操作不影响答案。

则有Xi,j=14((x,y) is next to (i,j)Xx,y)+Tx,y

于是可以直接高斯消元得到40分。

#6 B 40分
#include<bits/stdc++.h>
#define ll long long 
#define N 105
#define mod 998244353
#define I4 748683265
#define pii std::pair<int,int>
#define mp std::make_pair


int dx[] = {-1,0,1,-0};
int dy[] = {0,-1,0,1};

int n,X[N],Y[N],a[N][N],T[N],ans;

#define mpi std::map<pii,int>

mpi P,C;

inline ll qpow(ll a,ll b){
	ll res = 1;
	while(b){
		if(b & 1)res = res * a % mod;
		a = a * a % mod;
		b >>= 1; 
	}
	return res;
}

inline void guass(int n){	
	for(int i = 1;i <= n;++i){
		int pos = i;
		for(int j = i;j <= n;++j)
		if(a[j][i]){
			pos = j;
			break;
		}
		if(pos ^ i)std::swap(a[i],a[pos]);
		int w = qpow(a[i][i],mod - 2);
		for(int j = 1;j <= n;++j){
			if(j == i)continue;
			int t = 1ll * a[j][i] * w % mod;
			for(int k = i;k <= n + 1;++k)
			a[j][k] = ((a[j][k] - 1ll * t * a[i][k] % mod) % mod + mod) % mod;
		}		
	}	
	for(int i = 1;i <= n;++i)
	a[i][n + 1] = 1ll * (1ll * a[i][n + 1] * (mod - 1) % mod * qpow(a[i][i],mod - 2)) % mod;
}

inline void solve(){
	for(int i = 1;i <= n;++i){
//		std::cout<<"DEL "<<i<<std::endl;
		for(int j = 0;j < 4;++j){
			int x = X[i] + dx[j],y = Y[i] + dy[j];
//			std::cout<<x<<" "<<y<<"\n";
			if(P.find(mp(x,y)) == P.end())continue;
			a[i][P[mp(x,y)]] = (I4) % mod; 
		}
		a[i][i] = mod - 1;
		a[i][n + 1] = T[i];
	}
	guass(n);
	for(auto i : C){
		int sx = i.first.first,sy = i.first.second,res = 0;
//		std::cout<<sx<<" "<<sy<<std::endl; 
		for(int j = 0;j < 4;++j){
			int nx = sx + dx[j];
			int ny = sy + dy[j];
			if(P.find(mp(nx,ny)) == P.end())continue;
			res = (res + a[P[mp(nx,ny)]][n + 1]) % mod;
		}
	ans = ans ^ (1ll * I4 * res % mod);
	}
	std::cout<<ans<<"\n";
}

int main(){
	scanf("%d",&n);
	for(int i = 1;i <= n;++i){
		scanf("%d%d%d",&X[i],&Y[i],&T[i]);
		P[mp(X[i],Y[i])] = i;
	}
	for(int i = 1;i <= n;++i)
	for(int j = 0;j < 4;++j){
		int x = X[i] + dx[j],y = Y[i] + dy[j];
		if(P.find(mp(x,y)) == P.end())C[mp(x,y)] = 1;
	}
	solve();
}


n2000时,考虑当我们每一列的元素只在[im,i+m]中有值可以稀疏矩阵消元。

但是我发现有份代码直接对矩阵随机打乱然后记录有元素的值,跑的也很快。

#6 B 60分
inline void guass(int n){
	std::random_shuffle(a+1,a+n+1);
	for(R int i=1;i<=n;++i)
		for(R int j=1;j<=n+1;++j) if(a[i][j]) mw[i].insert(j);
	for(R int i=1;i<=n;++i){
		R int j=i;
		for(;j<=n;++j) if(a[j][i]) break;
		if(j^i) std::swap(a[i],a[j]),std::swap(mw[i],mw[j]);
		R int ha=qpow(a[i][i],P-2);
		for(j=1;j<=n;++j){
			if(j==i) continue;
			if(mw[j].find(i)==mw[j].end())continue;
			R int qc=1LL*(P-a[j][i])*ha%P;
			for(auto k:mw[i]){
				if(!a[j][k]) mw[j].insert(k);
				a[j][k]=(a[j][k]+1LL*qc*a[i][k])%P;
				if(!a[j][k]) mw[j].erase(k);
			}
		}
	}
	for(R int i=1;i<=n;++i){
		a[i][n+1]=(a[i][n+1]*(P-1LL)%P*qpow(a[i][i],P-2))%P;
	}
}

考虑矩阵情况,可以直接手动消元把除第一列的元素都用第一列表示,最后使用最后一列的关系对其消元,这样只有O(n)个元,其复杂度为O(n32)

#7

A

考虑一次操作二会改变奇偶性。
一定是先操作二一次,然后再检查子区间是否有全偶区间即可。
当带0时,其把序列划分位若干子区间。
考虑扫描线即可。
找到前面第一个不是偶数的子区间即可。

image

B

xpp原本想考的是随机下最大上升子序列只有根号。

但是随机太好了。

被某些根号算法草爆了。

这里提供一个线段树覆盖代替原本的暴力并查集的做法。

点击查看代码
#include<bits/stdc++.h>
#define ll long long 
#define N 15005

int n,m,q,mx,a[N];

int sum[35000];

#define mid ((l + r) >> 1)
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)

using std::bitset;
using std::array;
using std::vector;

bitset<35000>tag;

vector<array<int,4>>M;

inline void cov(int u,int l,int r,int tl,int tr){
	if(tag[u])return ;
	if(tl <= l && r <= tr){tag[u] = 1,sum[u] = r - l + 1;return ;}
	if(tl <= mid)
	cov(ls(u),l,mid,tl,tr);
	if(tr > mid)
	cov(rs(u),mid + 1,r,tl,tr);
	tag[u] = tag[ls(u)] & tag[rs(u)],sum[u] = sum[ls(u)] + sum[rs(u)];
}

int main(){
	scanf("%d%d%d",&n,&m,&q);
	for(int i = 1;i <= n;++i){
		scanf("%d",&a[i]);
		M.push_back({i,i,a[i],0}); 
	}
	for(int i = 1;i <= m;++i){
		int l,r,x;
		scanf("%d%d%d",&l,&r,&x);
		M.push_back({l,r,x,i});
	}
	std::sort(M.begin(), M.end(), [&](array<int, 4> x, array<int, 4> y) { return x[2] < y[2]; });
	while(q -- ){
		int l1,r1,l2,r2;
		scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
		memset(sum,0,sizeof(sum)),tag.reset();
		ll ans = 0;
		int lst = 0;
		for (auto &p : M) if (!p[3] || p[3] >= l1 && p[3] <= r1) {
			int l = std::max(l2, p[0]), r = std::min(r2, p[1]);
			if (l <= r) cov(1, 1, n, l, r);
			ans += 1ll * p[2] * (sum[1] - lst);
			if ((lst = sum[1]) == r2 - l2 + 1) break;
		}
		printf("%lld\n", ans);		
	}	
}

#8

A

考虑 (si,si+1,ti,ti+1) 一定有两个相同,所以最长公共子序列长度至少为 n.

考虑限制很紧,一不小心就会大于 n

考虑只有两种情况:

ABABABAB  CCCC

ACACBCBC  BCBCACAC

对着检查即可。

点击查看代码
//晦暗的宇宙,我们找不到光,看不见尽头,但我们永远都不会被黑色打倒。——Quinn葵因
#include<bits/stdc++.h>
#define ll long long
#define N 2000005
#define mod 998244353

char s[N],t[N];

int n;

int T;

bool pre[N],suf[N];

bool check(char a,char b){
	return a == '?' || a == b;
}

ll ans = 0;

inline void calc(char a,char b,char c){
	int now = 1;
	for(int i = 1;i <= (n << 1) + 1;++i)
	if(i & 1)
	now = now * check(s[i],a) * check(t[i],c) % mod;
	else
	now = now * check(s[i],b) * (check(t[i],a) + check(t[i],b)) % mod;
	ans = (ans + now) % mod;
	now = 1;
	for(int i = 1;i <= (n << 1) + 1;++i)
	if(i & 1)
	now = now * check(t[i],a) * check(s[i],c) % mod;
	else
	now = now * check(t[i],b) * (check(s[i],a) + check(s[i],b)) % mod;
	ans = (ans + now) % mod;
	pre[0] = suf[2 * n + 2] = 1;
	for(int i = 1;i <= (n << 1) + 1;++i){
		if(i & 1)
		pre[i] = pre[i - 1] & check(s[i],a) & check(t[i],b);
		else
		pre[i] = pre[i - 1] & check(s[i],c) & check(t[i],c);
	}	
	for(int i =(n << 1) + 1;i >= 1;--i){
		if(i & 1)
		suf[i] = suf[i + 1] & check(s[i],b) & check(t[i],a);
		else
		suf[i] = suf[i + 1] & check(s[i],c) & check(t[i],c);
	}		
	for(int i = 1;i <= (n << 1) + 1;i += 2)
	ans += (i == ((n << 1) + 1)) ? - (pre[i] & suf[i + 1]) : pre[i] & suf[i + 1] ;
} 

int main(){
	scanf("%d",&T);
	while(T -- ){
		ans = 0; 
		scanf("%d%s%s",&n,s + 1,t + 1);
      	calc('A','B','C');
        calc('A','C','B');
        calc('B','A','C');
        calc('B','C','A');
        calc('C','A','B');
        calc('C','B','A');	
		std::cout<<ans<<"\n";
	}
}
/*
2
?????
?????
*/ 

B

考虑树上枚举 (x,y),LCAz

考虑当z<x<y或者 x<y<z 相当于给定了一个矩形,其矩形内的点均无效。

那么直接对询问扫描线即可。

考虑只要枚举相邻的x,y,那么直接树上启发式合并即可。

#10

C

先考虑菊花的做法,发现其等价于给定点权,一条边的代价为 abs(ax+ay)

其可以使用 Brovka 解决。

考虑改为任意树,可以使用点/边分治,将路径改为上述形式解决。

每一轮,每点均找到异子树内的最小权边,共有 nlog 条边。

使用边分治更好处理。

点击查看代码
//晦暗的宇宙,我们找不到光,看不见尽头,但我们永远都不会被黑色打倒。——Quinn葵因
#include<bits/stdc++.h>
#define ll long long
#define N (int)2e6

using std::vector;
using std::pair;

#define pii pair<int,int>
#define mp std::make_pair

int head[N];

struct P{
	int to,next,w;
}E[N * 20];

int cnt = 1;

inline void add(int u,int v,int w){
	E[++cnt].to = v;
	E[cnt].next = head[u];
	E[cnt].w = w;
	head[u] = cnt;
}

inline void adde(int u,int v,int w){
	add(u,v,w);
	add(v,u,w);
}

vector<pii>G[N];

int m;

inline void reb(int u,int fa){
	int lst = 0;
	for(auto vi : G[u]){
		int v = vi.first;
		int w = vi.second;
		if(v == fa)continue;
		if(!lst){
			adde(u,v,w);
			lst = u;
		}else{
			adde(lst,++m,0);
			adde(m,v,w);
			lst = m;
		}
		reb(v,u);
	}
}

int siz[N],re,minn,sum;

int vis[N];

inline void getroot(int u,int fa){
	siz[u] = 1;
	for(int i = head[u];i;i = E[i].next){
		int v = E[i].to;
		if(v == fa || vis[i])continue;
		getroot(v,u);
		siz[u] += siz[v];
		if(std::max(siz[v],sum - siz[v]) < minn)
		minn = std::max(siz[v],sum - siz[v]),re = i;
	}
}

ll dis[N];

int ent;

struct nod {
	int u,v;
	ll w;
	nod(){}
	nod(int _u,int _v,ll _w){u = _u,v = _v,w = _w;}
}e[N * 40];

bool operator < (nod A,nod B){
	return A.w < B.w;
}

int fa[N];

inline int find(int x){return (x == fa[x]) ? x : fa[x] = find(fa[x]);}

pair<ll,int>Vec[3][N];

int sig[3];

inline void calc(int u,int tag,int fa){
	Vec[tag][++sig[tag]] = mp(dis[u],u);
	for(int i = head[u];i;i = E[i].next){
		int v = E[i].to;
		int w = E[i].w;
		if(v == fa || vis[i])continue;
		dis[v] = dis[u] + w;
		calc(v,tag,u);
	}
}

inline ll llabs(ll x){return x > 0 ? x : -x;}

inline void solve(int u){
	if(sum == 1)return;
	minn = 1e9;getroot(u,0);
	vis[re] = vis[re ^ 1] = 1;
//	std::cout<<u<<" "<<sum<<" "<<re<<"\n";
	int x = E[re].to,y = E[re ^ 1].to;
	sig[1] = sig[2] = 0;
	dis[x] = E[re].w;calc(x,1,0);
	dis[y] = 0;calc(y,2,0);
	std::sort(Vec[1] + 1,Vec[1] + sig[1] + 1);
	std::sort(Vec[2] + 1,Vec[2] + sig[2] + 1);
	for(int i=1,j=sig[2];i<=sig[1];i++) {
		while(j&&Vec[2][j].first>-Vec[1][i].first) j--;
		if(j+1<=sig[2]) e[++ent]=nod(Vec[1][i].second,Vec[2][j+1].second,llabs(Vec[1][i].first+Vec[2][j+1].first));
		if(j) e[++ent]=nod(Vec[1][i].second,Vec[2][j].second,llabs(Vec[1][i].first+Vec[2][j].first));
	}
	std::swap(sig[1],sig[2]);
	for(int i=1;i<=std::max(sig[1],sig[2]);i++) swap(Vec[1][i],Vec[2][i]);
	for(int i=1,j=sig[2];i<=sig[1];i++) {
		while(j&&Vec[2][j].first>-Vec[1][i].first) j--;
		if(j+1<=sig[2]) e[++ent]=nod(Vec[1][i].second,Vec[2][j+1].second,llabs(Vec[1][i].first+Vec[2][j+1].first));
		if(j) e[++ent]=nod(Vec[1][i].second,Vec[2][j].second,llabs(Vec[1][i].first+Vec[2][j].first));
	}
	int now = sum - siz[x];
	sum = siz[x];
	solve(x);
	sum = now;
	solve(y);
}

int n;

int main(){
//	freopen("q.in","r",stdin);
//	freopen("q.ans","w",stdout);
	scanf("%d",&n);
	m = n;
	for(int i = 1;i < n;++i){
		int x,y,w;
		scanf("%d%d%d",&x,&y,&w);
		G[x].emplace_back(y,w);
		G[y].emplace_back(x,w);
	}
	reb(1,0);
	sum = m;
	solve(1);
	std::sort(e + 1,e + ent + 1);
	ll ans = 0;
	for(int i = 1;i <= m;++i)fa[i] = i;
	for(int i = 1;i <= ent;++i){
//		std::cout<<e[i].u<<" "<<e[i].v<<" "<<e[i].w<<"\n";
		if(find(e[i].u) ^ find(e[i].v)){
			fa[fa[e[i].u]] = fa[e[i].v];
			ans += e[i].w;
		}
	}
	std::cout<<ans<<"\n";
}

本文作者:fhq_treap

本文链接:https://www.cnblogs.com/dixiao/p/15942900.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   fhq_treap  阅读(147)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起