• Codeforces 938G 线段树分治 线性基 可撤销并查集


    Codeforces 938G Shortest Path Queries

    一张连通图,三种操作

    1.给x和y之间加上边权为d的边,保证不会产生重边

    2.删除x和y之间的边,保证此边之前存在

    3.询问x到y的路径异或最小值

    保证图在任意时刻连通

    首先连通图路径异或相当于从x到y的任意一条路径再异或上若干个环得到的,只要在dfs过程中把非树边成的环丢到线性基里就好了,其他环一定可以通过这些环异或组合出来

    有加边删边操作怎么做呢?线段树时间分治!注意到不能保证在线段树的任意一个节点图是连通的,需要用可撤销并查集来维护,总复杂度(O(qlog(n)log(q)))

    tips:其实线性基因为一次插入只有一个赋值操作也可以用同样的方式撤销,不一定要每次都复制一遍下传

    //segment tree divide and conquer
    //linear base, dsu(rollback)
    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 2e5 + 10;
    
    struct Linear_Base {
    	int a[30];
    	Linear_Base() {memset(a, 0, sizeof(a));}
    	void insert(int val) {
    		for(int i = 29; ~i; --i) {
    			if((val >> i) & 1) {
    				if(a[i] == 0) {
    					a[i] = val;
    					return;
    				}
    				val ^= a[i];
    			}
    		}
    	}
    	int query(int val) {
    		for(int i = 29; ~i; --i)
    			val = min(val, val ^ a[i]);
    		return val;
    	}
    };
    
    pair<int*, int> save[N * 10];
    int top;
    
    void change(int &address, int val) {
    	save[top++] = make_pair(&address, address);
    	address = val;
    }
    
    void rollback(int st) {
    	while(st != top) {
    		top--;
    		*save[top].first = save[top].second;
    	}
    }
    
    struct edge {
    	int x, y, d;
    	edge() {x = y = d = 0;}
    	edge(int _x, int _y, int _d) : x(_x), y (_y), d(_d) {}
    };
    
    struct que {
    	int x, y, id;
    	que() {x = y = id = 0;}
    	que(int _x, int _y, int _id) : x(_x), y (_y), id(_id) {}
    };
    
    int ans[N], tot;
    
    vector<edge> G[N << 2];
    vector<que> Q[N << 2]; 
    
    int dsu[N], size[N], dis[N];
    
    int find(int x) {
    	return x == dsu[x] ? x : find(dsu[x]);
    }
    
    int get_dist(int x) {
    	return x == dsu[x] ? 0 : dis[x] ^ get_dist(dsu[x]); 
    }
    
    int unite(int x, int y, int d) {
    	d ^= get_dist(x);
    	d ^= get_dist(y);
    	x = find(x);
    	y = find(y);
    	if(x == y) 
    		return 0;
    	if(size[x] < size[y]) swap(x, y);
    	change(size[x], size[x] + size[y]);
    	change(dsu[y], x);
    	change(dis[y], d);
    	return 1;
    }
    
    void update(int rt, int l, int r, int L, int R, const edge &x) {
    	if(L <= l && r <= R) {G[rt].push_back(x); return;}
    	int mid = l + r >> 1;
    	if(L <= mid) update(rt << 1, l, mid, L, R, x);
    	if(R > mid) update(rt << 1 | 1, mid + 1, r, L, R, x);
    }
    
    void add_query(int rt, int l, int r, int pos, const que &x) {
    	if(l == r) {Q[rt].push_back(x); return;}
    	int mid = l + r >> 1;
    	if(pos <= mid) add_query(rt << 1, l, mid, pos, x);
    	else add_query(rt << 1 | 1, mid + 1, r, pos, x);
    }
    
    void dfs(int rt, int l, int r, Linear_Base Base) {
    	int st = top;
    	for(auto e : G[rt]) {
    		if(!unite(e.x, e.y, e.d)) {
    			Base.insert(get_dist(e.x) ^ get_dist(e.y) ^ e.d);
    		}
    	}
    	if(l == r) {
    		for(auto q : Q[rt]) 
    			ans[q.id] = Base.query(get_dist(q.x) ^ get_dist(q.y));
    	}
    	else {
    		int mid = l + r >> 1;
    		dfs(rt << 1, l, mid, Base);
    		dfs(rt << 1 | 1, mid + 1, r, Base);
    	}
    	rollback(st);
    }
    
    int n, m, q, op, x, y, d;
    map<pair<int, int>, pair<int, int>> st;
    
    int main() {
    	scanf("%d%d", &n, &m);
    	for(int i = 1; i <= n; ++i) dsu[i] = i, size[i] = 1, dis[i] = 0;
    	for(int i = 1; i <= m; ++i) {
    		scanf("%d%d%d", &x, &y, &d);
    		st[make_pair(x, y)] = make_pair(1, d);
    	}
    	scanf("%d", &q);
    	for(int i = 1; i <= q; ++i) {
    		scanf("%d%d%d", &op, &x, &y);
    		if(op == 1) {
    			scanf("%d", &d);
    			st[make_pair(x, y)] = make_pair(i, d);
    		}
    		else if(op == 2) {
    			update(1, 1, q, st[make_pair(x, y)].first, i, edge(x, y, st[make_pair(x, y)].second));
    			st.erase(make_pair(x, y));
    		}
    		else {
    			add_query(1, 1, q, i, que(x, y, ++tot));
    		}
    	}
    	for(auto e: st) {
    		update(1, 1, q, e.second.first, q, edge(e.first.first, e.first.second, e.second.second));
    	}
    	dfs(1, 1, q, Linear_Base());
    	for(int i = 1; i <= tot; ++i) {
    		printf("%d
    ", ans[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    One SQL to Rule Them All – an Efficient and Syntactically Idiomatic Approach to Management of Streams and Tables(中英双语)
    Spark 公共篇-InterfaceStability
    ANTLR v4 专业术语集
    Apache Spark as a Compiler: Joining a Billion Rows per Second on a Laptop(中英双语)
    Deep Dive into Spark SQL’s Catalyst Optimizer(中英双语)
    What’s new for Spark SQL in Apache Spark 1.3(中英双语)
    Scala 隐式(implicit)详解
    Introducing Apache Spark Datasets(中英双语)
    darknet-yolov3训练自己的数据集(转)
    NVIDIA显卡,显卡驱动版本,CUDA版本,cudnn版本之间兼容关系及如何选择
  • 原文地址:https://www.cnblogs.com/tusikalanse/p/11345944.html
Copyright © 2020-2023  润新知