zoukankan      html  css  js  c++  java
  • 线段树分治初步学习&洛谷P5227[AHOI2013]连通图

    线段树分治

    其实思想说起来是比较简单的,我们把这个题里的所有操作(比如连边删边查询balabala)全部拍到一棵线段树上,然后对着整棵树dfs一下求解答案,顺便把操作做一下,回溯的时候撤销一下即可。虽然有的操作需要以区间形式拍到树上,导致它可能会被拆成两个,但线段树的形态同样保证了操作最多只会被拆分(log(区间长度))次,保障了复杂度。

    洛谷P5227[AHOI2013]连通图

    传送门

    其实就是线段树分治+带撤销并查集,并查集写按秩合并,不能路径压缩(否则会破坏结构,就会撤销出奇怪的效果)
    以询问的时间轴为下标建一棵线段树,然后把边存在的时间区间拍到线段树上,用(vector)存下来,再对着树一波(dfs)记录答案,注意在叶节点不能写(return)我沙茶了,不然叶节点如果有操作就会还没撤销就返回了。
    md没有板对着敲自己yy着写好难受,码了一天

    /*P5227 [AHOI2013]连通图*/  
    #include <bits/stdc++.h>
    #define N (100000 + 5)
    using namespace std;
    inline int read() {
    	int cnt = 0, f = 1; char c = getchar();
    	while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
    	while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + c - '0'; c = getchar();}
    	return cnt * f;
    }
    int n, m, k, c, x, top;
    int fa[N];
    struct node {
    	int u, v;
    }edge[N << 1];
    struct node2 {
    	int siz, dep, fa;
    	node2(int siz_ = 1, int dep_ = 1, int fa_ = 0) : siz(siz_), dep(dep_), fa(fa_){};
    }bcj[N << 1], ctrl_Z[N << 1];
    int cur[N << 1], top2;
    int pre[N << 1];
    int get_father(int x) {return x == bcj[x].fa ? x : get_father(bcj[x].fa);}
    void merge(int p, int q) {
    	int x = get_father(p), y = get_father(q);
    	if (x == y) return;
    	if (bcj[x].dep > bcj[y].dep) swap(x, y);
    	ctrl_Z[++top] = bcj[x];
    	ctrl_Z[++top] = bcj[y];
    	bcj[x].fa = y, bcj[y].dep = max(bcj[y].dep, bcj[x].dep + 1), bcj[y].siz += bcj[x].siz;
    	cur[++top2] = x;
    	cur[++top2] = y;
    }
    struct node3{
    	int l, r;
    	vector<node> E;
    	#define l(p) tree[p].l
    	#define r(p) tree[p].r
    }tree[N << 2];
    
    void build(int l, int r, int p) {
    	l(p) = l, r(p) = r;
    	if (l == r) return;
    	int mid = (l + r) >> 1;
    	build (l, mid, p << 1);
    	build (mid + 1, r, p << 1 | 1);
    }
    
    void insert(node x, int l, int r, int p) {
    	if (l <= l(p) && r >= r(p)) { tree[p].E.push_back(x); return; }
    	register int mid = (l(p) + r(p)) >> 1;
    	if (l <= mid) insert(x, l, r, p << 1);
    	if (r > mid) insert(x, l, r, p << 1 | 1);
    }
    void dfs_(int p) {
    	int tp = top2;
    	for (register unsigned int i = 0; i < tree[p].E.size(); i++) {
    		node now = tree[p].E[i];
    		merge(now.u, now.v);
    	}
    	if (l(p) == r(p)) {
    		int now = bcj[get_father(1)].siz;
    		printf(now == n ? "Connected
    " : "Disconnected
    ");
    	} else dfs_(p << 1), dfs_(p << 1 | 1);
    	for (; top2 > tp; --top2, --top) {bcj[cur[top2]] = ctrl_Z[top];}
    }
    
    int main() {
    	n = read(), m = read();
    	for (register int i = 1; i <= n; i++) bcj[i] = node2(1, 1, i);
    	for (register int i = 1; i <= m; i++) 
    		edge[i].u = read(), edge[i].v = read(), pre[i] = 1;
    	k = read();
    	build (1, k, 1);
    	for (register int i = 1; i <= k; i++) {
    		c = read();
    		for (register int j = 1; j <= c; j++) {
    			x = read();
    			if (pre[x] < i) insert(edge[x], pre[x], i - 1, 1);
    			pre[x] = i + 1;
    		}
    	}
    	for (register int i = 1; i <= m; i++) {
    		if (pre[i] <= k) insert(edge[i], pre[i], k, 1);
    	}
    	dfs_(1);
    	return 0;
    } 
    
  • 相关阅读:
    【转】Intel Atom手机处理器“上窜下跳”
    神奇HVXC的MOS 分
    Skype 将支持 WebRTC 标准
    一篇文章算市值
    算法经典趣题三色旗
    Java基础(2)Java三大版本/体系
    一天一个 Linux 命令(27):mkfs 命令
    Java基础(1)Java特性及优势
    一天一个 Linux 命令(26):fdisk 命令
    关于Java中的整数类型值比较的疑问
  • 原文地址:https://www.cnblogs.com/kma093/p/11275762.html
Copyright © 2011-2022 走看看