首页 > 其他分享 >闲话 22.11.15

闲话 22.11.15

时间:2022-11-15 19:47:24浏览次数:81  
标签:cnt 15 fa int 闲话 ret st 22.11 return

闲话

幸亏昨天写了两道题 要不然今天没题可写了(
明天学考?

话说怎么那么多 bitmask 题啊

杂题

CF487E

Cyberland 有 \(n\) 座城市,编号从 \(1\) 到 \(n\),有 \(m\) 条双向道路连接这些城市。第 \(j\) 条路连接城市 \(a_j\) 和 \(b_j\)。每天,都有成千上万的游客来到 Cyberland 游玩。在每一个城市,都有纪念品售卖,第 \(i\) 个城市售价为 \(w_i\)。这个售价有时会变动。

每一个游客的游览路径都有固定起始城市和终止城市,且不会经过重复的城市。他们会在路径上的城市中,售价最低的那个城市购买纪念品。你能求出每一个游客在所有合法的路径中能购买的最低售价是多少吗?

你要处理 \(q\) 个操作:

C a w: 表示 \(a\) 城市的纪念品售价变成 \(w\)。
A a b: 表示有一个游客要从 \(a\) 城市到 \(b\) 城市,你要回答在所有他的旅行路径中最低售价的最低可能值。

\(1\le n, m, q \le 10^5\)。

经典图论题。

首先考虑树上怎么做。显然树剖求路径最小值 \(O(n\log ^2 n)\)。
然后考虑扔到图上。我们需要转化成树上问题。

建立广义圆方树,圆点权值是自己,方点权值是它链接的点的权值……吗?
考虑一棵菊花树。我们发现一个圆点可以链接一堆方点。这样直接修改单次可能会改动 \(O(n)\) 个方点的信息。这是不优的。
不妨令 \(1\) 为根,钦定一个树上父子关系。我们令一个方点维护自己儿子的信息,当路径 LCA 是方点时加入 LCA 的父亲的信息。

总时间复杂度 \(O(n \log^2 n)\)。

code
#include <bits/stdc++.h>
using namespace std; using pii = pair<int,int>;
using ll = long long; using ull = unsigned long long; using db = double; using ld = long double; using lll = __int128_t;
mt19937_64 rnd(chrono::steady_clock::now().time_since_epoch().count());
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
#define pre(i,s,t) for (register int i = (s), i##_ = (t) - 1; i > i##_; -- i)
const int N = 1e5 + 10;
const int inf = 0x3f3f3f3f;

int n, m, q, w[N << 1], t1, t2;
char typ;
vector<int> gr[N], tr[N << 1];

int dfn[N << 1], low[N], stp, cnt;
int stk[N], tp;
void tarjan(int u) {
	dfn[u] = low[u] = ++ stp; stk[++tp] = u;
	for (auto v : gr[u]) {
		if (!dfn[v]) {
			tarjan(v);
			low[u] = min(low[u], low[v]);
			if (low[v] >= dfn[u]) {
				int t = -1; ++ cnt;
				do {
					t = stk[tp --];
					tr[t].emplace_back(cnt); tr[cnt].emplace_back(t);
				} while (t != v);
				tr[u].emplace_back(cnt); tr[cnt].emplace_back(u);
			}
		} else 
			low[u] = min(low[u], dfn[v]);
	}
}

int fa[N << 1], dep[N << 1], idfn[N << 1], siz[N << 1], son[N << 1], top[N << 1];
void find_hc(int u, int f) {
	dep[u] = dep[f] + 1, fa[u] = f, siz[u] = 1;
	for (auto v : tr[u]) if (v != f) {
		find_hc(v, u); siz[u] += siz[v];
		if (siz[v] > siz[son[u]]) son[u] = v;
	}
}

void con_hc(int u, int tp) {
	dfn[u] = ++ stp; idfn[stp] = u; top[u] = tp;
	if (son[u]) con_hc(son[u], tp);
	for (auto v : tr[u]) if (v != fa[u] and v != son[u]) con_hc(v, v);
}

multiset<int> st[N];

class SegmentCitrus {
	#define ls (p << 1)
	#define rs (p << 1 | 1)
	
	int seg[N << 3];
	void ps_p(int p) { seg[p] = min(seg[ls], seg[rs]); }

	void build(int p, int l, int r) {
		if (l == r) {
			seg[p] = w[idfn[l]];
			return;
		} int mid = l + r >> 1;
		build(ls, l, mid); build(rs, mid+1, r);
		ps_p(p);
	}
	
	void update(int p, int l, int r, int pos, int val) {
		if (l == r) { 
			seg[p] = val;
			return;
		} int mid = l + r >> 1;
		if (pos <= mid) update (ls, l, mid, pos, val);
		else update (rs, mid + 1, r, pos, val);
		ps_p(p);
	}

	int query(int p, int l, int r, int L, int R) {
		if (L <= l and r <= R) return seg[p];
		int mid = l + r >> 1, ret = inf; 
		if (L <= mid) ret = min(ret, query(ls, l, mid, L, R)); 
		if (mid < R) ret = min(ret, query(rs, mid+1, r, L, R));
		return ret;
	}
    int query(int l, int r) { return query(1, 1, cnt, l, r); }

  public :
	void build() { build(1, 1, cnt); }

	int path(int u, int v) {
		int ret = inf;
		while (top[u] != top[v]) {
			if (dep[top[u]] < dep[top[v]]) swap(u, v);
			ret = min(ret, query(dfn[top[u]], dfn[u]));
			u = fa[top[u]];
		} if (dep[u] > dep[v]) swap(u, v);
		ret = min(ret, query(dfn[u], dfn[v]));
		if (u > n) ret = min(ret, w[fa[u]]);
		return ret;
	}

	void update(int p, int v) { update(1, 1, cnt, dfn[p], v); }
} Tr;

void update(int u, int val) {
	Tr.update(u, val);
	if (u == 1) {
		w[u] = val;
		return;
	} st[fa[u] - n].erase(st[fa[u] - n].find(w[u]));
	st[fa[u] - n].insert(val); w[u] = val;
	if (w[fa[u]] != *st[fa[u] - n].begin()) 
		Tr.update(fa[u], *st[fa[u] - n].begin()), w[fa[u]] = *st[fa[u] - n].begin();
}

signed main() { 
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin >> n >> m >> q; rep(i,1,n) cin >> w[i];
	rep(i,1,m) cin >> t1 >> t2, gr[t1].emplace_back(t2), gr[t2].emplace_back(t1);
	cnt = n; rep(i,1,n) if (!dfn[i]) tarjan(i);
	stp = 0; find_hc(1, 0); con_hc(1, 1);
	rep(i,2,n) st[fa[i] - n].emplace(w[i]);
	rep(i,n+1,cnt) w[i] = st[i - n].size() ? *st[i - n].begin() : inf;
	Tr.build();
	while (q--) {
		cin >> typ >> t1 >> t2;
		if (typ == 'C') {
			update(t1, t2);
		} else {
			cout << Tr.path(t1, t2) << '\n';
		}
	}
} 



[IPSC2016] Counting Swaps
给定你一个 \(1∼n\) 的排列 \(p\),可进行若干次操作,每次选择两个整数 \(x,y\),交换 \(p_x,\ p_y\)。

请输出用最少的操作次数将给定排列变成单调上升的序列的操作方案数对 \(10^9+9\) 取模的结果。

记置换环数为 \(\text{cnt}\),第 \(i\) 个环的大小为 \(s_i\)。
操作方案比较典。\(n - \text{cnt}\) 就是答案。

然后首先有各个环操作彼此独立,先乘进一个 \(\frac{(n-\text{cnt})!}{\prod_{i=1}^{\text{cnt}}(s_i-1)!}\),然后我们只需要乘入每个环的可能性。
对于一个环 \(i\),考虑使用图论模型计数。交换其中两个元素 \(p_x,\ p_y\) 后加一条边 \((x,y)\)。交换 \(s_i-1\) 次,两个元素不会被重复交换,且不会交换相同元素。这给出了一棵有标号无根树。因此对不同的操作方案计数树得到了总可能的方案数 \(s_i^{s_i-2}\)。

乘起来得到总方案数

\[\prod_{i=1}^\text{cnt} s_i^{s_i-2}\times \frac{(n-\text{cnt})!}{\prod_{i=1}^{\text{cnt}}(s_i-1)!} \]

计算即可。总时间复杂度 \(O(n)\)。

code
const int N = 5e5 + 10;
const int inf = 0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3fll;

const int mod = 1e9 + 9;
const int inv2 = (mod + 1) >> 1;
template <typename T1, typename T2> T1 add(T1 a, T2 b) { return (a += b) >= mod ? a - mod : a; }
template <typename T1, typename ...Args> T1 add(T1 a, Args ... b) { return add(a, add(b...)); }
struct FastMod { int m; ll b; void init(int _m) { m = _m; if (m == 0) m = 1; b = ((lll)1<<64) / m; } FastMod(int _m) { init(_m); } int operator() (ll a) {ll q = ((lll)a * b) >> 64; a -= q * m; if (a >= m) a -= m; return a; } } Mod(mod);
int mul(int a, int b) { return Mod(1ll * a * b); } template <typename ...Args> int mul(int a, Args ...b) { return mul(a, mul(b...)); }
template <typename T1, typename T2> T1 qp(T1 a, T2 b) { T1 ret = 1; for (; b > 0; a = mul(a, a), b >>= 1) if (b & 1) ret = mul(ret, a); return ret; }

int T, n, a[N], siz[N], cnt, fac[N], inv[N], ans = 1;
bool vis[N];

int main() {
	get(T); 
	fac[0] = fac[1] = inv[0] = inv[1] = 1; 
	rep(i,2,100000) fac[i] = mul(i, fac[i - 1]), inv[i] = mul(mod - mod / i, inv[mod % i]);
	rep(i,2,100000) inv[i] = mul(inv[i], inv[i - 1]);
	while (T--) {
		get(n); rep(i,1,n) get(a[i]), vis[i] = false;
		cnt = 0, ans = 1;
		for (int i = 1, ptr; i <= n; ++ i) if (!vis[i]) {
			vis[i] = 1; cnt ++; ptr = a[i]; siz[cnt] = 1;
			while (ptr != i) vis[ptr] = 1, ptr = a[ptr], siz[cnt] ++;
		} 
		rep(i,1,cnt) ans = mul(ans, qp(siz[i], siz[i] - 2), inv[siz[i] - 1]);
		ans = mul(ans, fac[n - cnt]);
		cout << ans << '\n';
	}
}

标签:cnt,15,fa,int,闲话,ret,st,22.11,return
From: https://www.cnblogs.com/joke3579/p/chitchat221115.html

相关文章

  • 15.运算符
    分类===类型和值都相等!==值和类型有一个不相等或两个都不相等......
  • 20221115面试题
    XXXXX一面vue3APIref和reactivevue-router的两种模式hashhistory区别vuexmutation同步action异步commit调用mutation方法dispatch调用action方法大屏经验地......
  • 【建议收藏】15755字,讲透MySQL性能优化(包含MySQL架构、存储引擎、调优工具、SQL、索引
    0.目录1)MySQL总体架构介绍2)MySQL存储引擎调优3)常用慢查询分析工具4)如何定位不合理的SQL5)SQL优化的一些建议1MySQL总体架构介绍1.1MySQL总体架构介绍引言MySQL......
  • [oeasy]python0015_十六进制_hexadecimal_字节形态_hex函数
    ​ 十六进制(hexadecimal)回忆上次内容上次数制可以转化bin(n)可以把数字转化为​​2进制​binary接收一个整数(int)得到一个二进制数形式的字符串​编......
  • CF1598F RBS 题解
    题意给\(n\)个串,求将这\(n\)个串以任意顺序接起来的最大的是合法括号序列的前缀数。分析\(n\)很小,考虑状压dp。有一个很典的转化是将(看成\(+1\),将)看成\(-......
  • 11.15
    今日内容1.软件开发架构2.网络编程简介3.OSI七层协议简介4.物理连接层5.数据链路层6.网络层7.传输层8.网络相关专业名词1.软件开发架构1.C/S架构Client:客户端......
  • 20221115_T4B_折半搜索双指针
    题意市面上共有\(n\)张门票,方便起见,我们把它们从\(1\)至\(n\)编号。其中,\(i\)号门票对应的场次为第\(b_i,1\leqb_i\leqk)\)场,价格为\(c_i\)元,且座位的排数为......
  • test20221115 打铁记
    总述\(53+20+20+0=93\),班上\(rk9\),太菜了。考场T1特殊性质+暴力(可是没有打满),T2特殊性质,T3暴力。费时\(40\)分钟,剩下的时间写正解(没写出来)+摆烂。感谢cy同志让......
  • 20221115_T3A+_贪心二分
    题意你在和Yazid做游戏。Yazid给了你一棵\(n\)个节点的树,并让你删除这棵树上的恰好\(k\)条边,使得整棵树被分成\(k+1\)个连通块。你觉得太简单了,随便删k条边......
  • 11月15日内容总结——
    目录一、软甲开发架构二、架构总结三、网络编程前戏四、OSI七层协议简介五、OSI协议之物理连接层六、OSI七层协议之数据链路层七、网络相关专业名词八、OSI七层协议之网络......