痛苦在虚无中回荡 神最终恩赐了绝望 是爱恨交织的冲撞 你永无力再违抗

test38

老师,给我们做这种模拟赛良心不会痛吗?


重建道路

首先你选边肯定不能破坏原有的连通性不然次数就不是最小的了,然后考虑初始连通块的最小点分别是 \(p_1,\dots,p_m\),你会选择依次将 \(p_1\)\(p_2,\dots,p_m\) 连接。现在只用考虑删掉的边集最好是什么, 你想顺着字典序依次枚举每一条边,如果删除不影响连通性就用来删除,但这个过程不好维护,不过显然你可以贪心,倒着字典序做能加就加肯定不劣,剩下的边就是可以选的。

#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define fir first
#define sec second

using namespace std;

const int N=200005;

int T, n, m, dsu[N];
struct node {
	int x, y;
	bool operator<(const node &rhs) const { return x==rhs.x?y<rhs.y:x<rhs.x; }
} p[N];

int get(int x) { return x==dsu[x]?x:dsu[x]=get(dsu[x]); }

void mian() {
	cin >> n >> m;
	up(i,1,m) {
		cin >> p[i].x >> p[i].y;
		if(p[i].y<p[i].x) swap(p[i].x,p[i].y);
	}
	sort(p+1,p+1+m);
	up(i,1,n) dsu[i]=i;
	dn(i,m,1) {
		int x=get(p[i].x), y=get(p[i].y);
		if(x==y) continue;
		dsu[y]=x, p[i].x=p[i].y=0;
	}
	int j=0, u=1;
	vector<pair<pii,pii> > ans;
	up(i,1,n) if(dsu[i]==i) {
		if(j) {
			while(u<=m&&!p[u].x) ++u;
			if(u>m) {
				cout << -1 << '\n';
				return;
			}
			ans.pb(mp(mp(p[u].x,p[u].y),mp(j,i)));
			++u;
		}
		else j=i;
	}
	cout << ans.size() << '\n';
	for(pair<pii,pii> u:ans) cout << u.fir.fir << ' ' << u.fir.sec << ' ' << u.sec.fir << ' ' << u.sec.sec << '\n';
}

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> T;
	while(T--) mian();
	return 0;
}

随机爬树

你这个保证 \(sum_u\) 不是 \(P\) 的倍数。

对每一个 \(a_i\) 考虑贡献,是 \(a_i\times \prod_{u\to i} \frac{w_i}{sum_{fa_u}}\),累乘再累加,\(w_u\)\(u\) 的子树贡献,\(sum_u\) 对子树中除了根贡献,这些在 dfn 上面是点/区间,线段树维护即可。

#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define int long long 
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pb push_back
#define ls(p) (p<<1)
#define rs(p) (p<<1|1) 

using namespace std;

const int N=100005, P=998244353;

inline int ksm(int a,int b=P-2) {
	int ret=1;
	for( ; b; b>>=1) {
		if(b&1) ret=ret*a%P;
		a=a*a%P;
	}
	return ret;
}

int n, T, stp, fa[N], L[N], R[N], w[N], sum[N], a[N];
int tr[N<<2], mul[N<<2];
vector<int> to[N];

void dfs(int x) {
	L[x]=++stp;
	for(int y:to[x]) (sum[x]+=w[y])%=P, dfs(y);
	R[x]=stp;
}

inline void tup(int p) {
	tr[p]=(tr[ls(p)]+tr[rs(p)])%P;
}

inline void tdn(int p) {
	(mul[ls(p)]*=mul[p])%=P, (tr[ls(p)]*=mul[p])%=P;
	(mul[rs(p)]*=mul[p])%=P, (tr[rs(p)]*=mul[p])%=P;
	mul[p]=1;
}

void build(int p=1,int s=1,int e=n) {
	mul[p]=1;
	if(s==e) { tr[p]=1; return; }
	int mid=(s+e)>>1;
	build(ls(p),s,mid), build(rs(p),mid+1,e);
	tup(p); 
}

void modify(int l,int r,int v,int p=1,int s=1,int e=n) {
	if(l<=s&&e<=r) {
		(mul[p]*=v)%=P, (tr[p]*=v)%=P;
		return;
	}
	tdn(p);
	int mid=(s+e)>>1;
	if(l<=mid) modify(l,r,v,ls(p),s,mid);
	if(r>mid) modify(l,r,v,rs(p),mid+1,e);
	tup(p); 
}

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n;
	up(i,2,n) {
		cin >> fa[i];
		to[fa[i]].pb(i);
	}
	up(i,1,n) cin >> w[i];
	up(i,1,n) cin >> a[i];
	dfs(1), build();
	up(i,1,n) {
		modify(L[i],L[i],a[i]);
		if(i>1) modify(L[i],R[i],w[i]);
		if(sum[i]) {
			modify(L[i],R[i],ksm(sum[i]));
			modify(L[i],L[i],sum[i]); 	
		}
	}
	cout << (tr[1]%P+P)%P << '\n';
	cin >> T;
	while(T--) {
		int u, W, A;
		cin >> u >> W >> A;
		modify(L[u],L[u],ksm(a[u])*A%P), a[u]=A;
		if(u>1) {
			int nxt=((sum[fa[u]]+(W-w[u]))%P+P)%P;
			modify(L[fa[u]],R[fa[u]],sum[fa[u]]*ksm(nxt)%P);
			modify(L[fa[u]],L[fa[u]],ksm(sum[fa[u]])*nxt%P);
			sum[fa[u]]=nxt;
			modify(L[u],R[u],ksm(w[u])*W%P), w[u]=W;
		}
		cout << (tr[1]%P+P)%P << '\n';
	}
	return 0;
}

交集

你维护出某个点在左边/右边的连通块,两个并查集祖先都相等的可以相互访问。

#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pb push_back

using namespace std;

const int N=300005;

int n, ml, mr, ans[N], cnt[N];
vector<int> sav[N];
struct DSU {
	int dsu[N];
	void clear() {
		up(i,1,n) dsu[i]=i;
	}
	int get(int x) {
		if(x==dsu[x]) return x;
		return dsu[x]=get(dsu[x]);
	}
	void merge(int x,int y) {
		x=get(x), y=get(y);
		if(x!=y) dsu[x]=y;
	}
} L, R;

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> ml >> mr;
	L.clear(), R.clear();
	while(ml--) {
		int u, v;
		cin >> u >> v;
		L.merge(u,v);
	}
	while(mr--) {
		int u, v;
		cin >> u >> v;
		R.merge(u,v);
	}
	up(i,1,n) sav[L.get(i)].pb(i);
	up(i,1,n) if(sav[i].size()) {
		int res=0;
		for(int u:sav[i]) ++cnt[R.get(u)];
		for(int u:sav[i]) ans[u]=cnt[R.get(u)];
		for(int u:sav[i]) --cnt[R.get(u)];
	}
	up(i,1,n) cout << ans[i] << ' ';
	return 0;
}

地铁换乘

\(c\) 相等的且连在一起的边有特殊贡献,具体而言买一次票两两通达,边又没多少你直接你新建一个出入代价都为 \(\frac{p_c}{2}\) 的点连上去就行了。

#pragma GCC optimize(1,2,3,"Ofast","inline")
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pii pair<int,int>
#define mp make_pair
#define pb push_back

using namespace std;

const int N=300005, M=1000005, inf=1e18;

int n, m, C, p[M], dsu[N], tot, dis[N], tag[N];
struct node { int x, y, w; } e[N];
vector<pii> to[N];
vector<int> gp[N];

int get(int x) { return x==dsu[x]?x:dsu[x]=get(dsu[x]); }

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m >> C, tot=n;
	up(i,1,C) cin >> p[i];
	up(i,1,m) cin >> e[i].x >> e[i].y >> e[i].w;
	sort(e+1,e+1+m,[](node i,node j){return i.w<j.w;});
	for(int l=1, r=1; l<=m; l=r+1, r=l) {
		while(r<m&&e[r+1].w==e[l].w) ++r;
		set<int> sav;
		up(i,l,r) {
			int x=e[i].x, y=e[i].y;
			dsu[x]=x, sav.insert(x);
			dsu[y]=y, sav.insert(y);
		}
		up(i,l,r) {
			int x=get(e[i].x), y=get(e[i].y);
			if(x!=y) dsu[x]=y;
		}
		for(int u:sav) gp[get(u)].pb(u);
		for(int u:sav) if(gp[u].size()) {
			++tot;
			for(int i:gp[u]) {
				to[i].pb(mp(tot,p[e[l].w]));
				to[tot].pb(mp(i,p[e[l].w]));
			}
			gp[u].clear();
		}
	}
	up(i,2,tot) dis[i]=inf;
	priority_queue<pii,vector<pii>,greater<pii> > q;
	q.push(mp(0,1));
	while(q.size()) {
		int x=q.top().second;
		q.pop();
		if(tag[x]) continue;
		tag[x]=1;
		for(pii u:to[x]) {
			int y=u.first, w=u.second;
			if(dis[x]+w<dis[y]) {
				dis[y]=dis[x]+w;
				q.push(mp(dis[y],y));
			}
		}
	}
	up(i,1,n) cout << (dis[i]==inf?-1:dis[i]/2) << ' ';
	return 0;
}
posted @ 2025-11-12 14:51  Hypoxia571  阅读(12)  评论(0)    收藏  举报