首页 > 其他分享 >[题解] CF938G Shortest Path Queries

[题解] CF938G Shortest Path Queries

时间:2023-11-09 21:49:17浏览次数:33  
标签:sz return int 题解 Read 异或 MAXN Queries Shortest

Shortest Path Queries

给你一张无向连通图,支持三种操作:

  1. 插入一条边 \((u, v, w)\)。
  2. 删除一条边。
  3. 求 \((u, v)\) 之间的异或最短路。

\(n, m, 1 < 2^{30}\)。

先考虑异或最短路怎么求,这部分和 最大XOR和路径 是一样的。就是把图上的环都扔到一个线性基里,每次查询就是线性基上查询异或最小值。
再考虑加上加边操作。就是维护一棵图的生成树,要是加入的这一条边没有形成环就把它加到生成树中,形成了环就是把环长扔到线性基里,环长可以通过生成树上到根的路径的异或和来算。这部分用并查集维护即可。
加上删边就是套一个线段树分治,再把并查集改成可撤销并查集。
时间复杂度 \(O(n \log^2 n)\)。

constexpr int MAXN = 2e5 + 9, MAXM = MAXN << 1;
int n, m, q, st[MAXM], ed[MAXM];
map<pii, int> idx;
pair<int, int> qry[MAXN];
array<int, 3> E[MAXM];

struct Base_Line {
	static constexpr int N = 31;
	int a[N];
	
	void Insert(int x) {
		for (int i = 30; ~i; i --) if (x >> i & 1) {
			if (a[i]) x ^= a[i];
			else { a[i] = x; break; }
		}
		return;
	}
	int Query(int x) {
		for (int i = 30; i >= 0; i --)
			if (x >> i & 1) x ^= a[i];
		return x;
	}
} ds;

struct Disjoint {
	int fa[MAXN], sz[MAXN], dis[MAXN];
	vector<pair<int, int> > stk;
	
	void Init(int n) {
		for (int i = 1; i <= n; i ++)
			fa[i] = i, dis[i] = 0, sz[i] = 1;
		return;
	}
	int Find(int u) {
		return fa[u] == u ? u : Find(fa[u]);
	}
	int Get_Dis(int u) {
		return fa[u] == u ? 0 : dis[u] ^ Get_Dis(fa[u]);
	}
	bool Merge(int u, int v, int w) {
		w ^= Get_Dis(u) ^ Get_Dis(v);
		u = Find(u), v = Find(v);
		if (u == v) return false;
		if (sz[u] > sz[v]) swap(u, v);
		stk.emplace_back(u, v);
		fa[u] = v, dis[u] ^= w, sz[v] += sz[u];
		return true;
	}
	void Reset() {
		auto [u, v] = stk.back(); stk.pop_back();
		fa[u] = u, sz[v] -= sz[u], dis[u] = 0; return;
	}
} D;

namespace Segment_Tree {
	vector<int> upd[MAXN << 2];
	
	void Update(int l, int r, int id, int L = 1, int R = q, int p = 1) {
		if (l <= L && R <= r) return upd[p].emplace_back(id), void();
		int Mid = L + R >> 1;
		if (l <= Mid) Update(l, r, id, L, Mid, p << 1);
		if (Mid < r) Update(l, r, id, Mid + 1, R, p << 1 | 1);
		return;
	}
	void Solve(int L = 1, int R = q, int p = 1) {
		int tp = D.stk.size();
		Base_Line ret = ds;
		auto Get_Dis = [&](int u, int v) { return D.Get_Dis(u) ^ D.Get_Dis(v); };
		for (auto i : upd[p]) {
			auto [u, v, w] = E[i];
			if (D.Find(u) == D.Find(v)) ds.Insert(Get_Dis(u, v) ^ w);
			else D.Merge(u, v, w);
		}
		int Mid = L + R >> 1;
		if (L == R) {
			auto [u, v] = qry[L];
			if (u) Write(ds.Query(Get_Dis(u, v)), '\n');
		}
		else Solve(L, Mid, p << 1), Solve(Mid + 1, R, p << 1 | 1);
		while (D.stk.size() ^ tp) D.Reset(); ds = ret;
		return;
	}
}

void slv() {
	n = Read<int>(), m = Read<int>();
	for (int i = 1; i <= m; i ++) {
		int u = Read<int>(), v = Read<int>(), w = Read<int>();
		E[i] = {u, v, w}, idx[make_pair(u, v)] = i, st[i] = 1, ed[i] = -1;
	}
	q = Read<int>();
	for (int i = 1; i <= q; i ++) {
		int opt = Read<int>();
		if (opt == 1) {
			int u = Read<int>(), v = Read<int>(), w = Read<int>();
			E[++ m] = {u, v, w}, idx[make_pair(u, v)] = m, st[m] = i, ed[m] = -1;
		} else if (opt == 2) {
			int u = Read<int>(), v = Read<int>();
			ed[idx[make_pair(u, v)]] = i - 1;
		} else {
			int u = Read<int>(), v = Read<int>();
			qry[i] = {u, v};
		}
	}
	for (int i = 1; i <= m; i ++) {
		if (ed[i] == -1) ed[i] = q;
		if (st[i] <= ed[i])Segment_Tree::Update(st[i], ed[i], i);
	}
	D.Init(n); Segment_Tree::Solve();
	return;
}

标签:sz,return,int,题解,Read,异或,MAXN,Queries,Shortest
From: https://www.cnblogs.com/definieren/p/17822922.html

相关文章

  • [题解] P5901 [IOI2009] Regions
    P5901[IOI2009]Regions给你一棵树,每个点有颜色\(h_i\)。多次询问,每次询问有多少对\((u,v)\)满足\(u\)是\(v\)的祖先且\(u\)的颜色是\(r_1\)且\(v\)的颜色是\(r_2\)。\(n,q\le2\times10^5,h_i\le2.5\times10^4\)。总颜色数一定,考虑对颜色的出现次......
  • [题解] CFgym103069G Prof. Pang's sequence
    G.Prof.Pang'ssequence给一个长度为\(n\)的序列\(a\),多次询问区间\([l,r]\)内有多少个子区间的颜色数是奇数。\(n,m\le10^5\)。先按照HH的项链的套路,对于每个数记一下\(lst_i\)表示\(a_i\)上一次出现的位置。然后扫描线,将所有子区间的答案转化成历史和。......
  • [CSP-J 2021] 小熊的果篮 题解
    题目链接既然只有两种东西,我们不妨分开考虑,这里也借鉴了很多二分图题目的切入点。假设苹果和桔子下标分别如下图所示:苹果:1367910桔子:2458那么第一次取,应该是这样取:1234689也就是先取开头比较小的,然后轮流取,注意一定保证递增,也就是对于苹果找出来的\(x\)......
  • [题解]CFgym103470E Paimon Segment Tree
    PaimonSegmentTree区间加,求一段时间内的区间平方和。\(n,m,q\le5\times10^4\)。对时间维差分一下,变成询问区间历史平方和。离线下来扫描线,扫描线维护时间维,数据结构维护序列维。考虑维护二元组\((a,s)\)表示当前位置值为\(a\),历史平方和为\(s\)。可以发现怎......
  • A2OJ Ladder 21 简要题解
    https://earthshakira.github.io/a2oj-clientside/server/Ladder21.html只记录Difficultylevel>=8的。有很多题是口胡的。写了的会标注提交记录。还有些很久以前写过的题就懒得搬提交记录了。71.CF444EDZYlovesplanting我们二分答案,然后可以这样转化:把权\(\ged\)的......
  • 题解:疯狂lcm
    %你赛打到一半来写个题解link:疯狂lcm题意,求:\[\sum_{i=1}^{n}lcm(i,n)\]不多说废话,直接开推:\[\begin{aligned}&=n\sum_{i=1}^{n}\frac{i}{gcd(i,n)}\\&=n\sum_{d\midn}\sum_{i=1}^{n}\frac{i}{d}[gcd(i,n)=d]\\&=n\sum_{d\midn}\sum_{i=1}^{n}......
  • KubeEdge部署 完美运行 附问题解决方法
    云端部署环境准备一、部署前工作(k8s、docker安装及配置、初始化集群、golang安装、keadm安装)配置网络参数cat>>/etc/hosts<<EOF#GitHubStart52.74.223.119github.com192.30.253.119gist.github.com54.169.195.247api.github.com185.199.111.153assets-cdn.gith......
  • linux/docker 版 Sql Server新建的数据库插入中文乱码问题解决方案
    SqlServer插入遇到乱码原因:在英文系统中,SqlServer默认排序规则为英文字典顺序解决方案一:容器版SqlServer,在创建容器时,可以加上环境变量-eMSSQL_COLLATION=Chinese_PRC_CI_AS-eTZ=Asia/Shanghai 把排序规则设为中文字典顺序并忽略大小写区分重音,时区设置为上海,不然......
  • CSP-S 2023 T1 题解
    CSP-S2023T1题解很简单,我们只需要暴力枚举五位密码,每次判断拨一个齿轮和两个齿轮能达到的状态数,如果等于\(n\),答案\(+1\)。时间复杂度\(O(10^5\times5n)\)。code#include<iostream>#include<algorithm>#include<cmath>#include<cstring>usingnamespacestd;......
  • P4069 题解
    简要题意给定一棵\(n\)个点的树,树有边权。对每个点维护一个集合\(S_u\),一开始集合均包含整数\(123456789123456789\)。设\({\rmdis}_{a,b}\)为树上两点\(a\),\(b\)的距离。共\(m\)次操作,分为如下两种:stab:设\(f\)为\(s\),\(t\)路径上的点集,对与\(\forall......