zoukankan      html  css  js  c++  java
  • CF487 E. Tourists [点双连通分量 树链剖分 割点]

    E. Tourists

    题意:

    无向连通图

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

    (1≤n,m,q≤10^5,1≤w_ile10^9)


    显然一个点双连通分量中想去任何点都是可以的。

    那么bcc缩点,树剖一下就好了?

    割点可以存在于多个bcc!

    所以把割点单独拿出来,向每个bcc连边


    修改割点的权值怎么办?

    每个割点的信息合并到父亲bcc里,查询的时候lca为bcc那么额外加上父亲割点的信息就行了


    同一个bcc以及孩子割点还要用个multiset维护才能字词修改...


    然后吐槽一下bcc,行为真的很奇怪啊,甚至(u—v)这样的东西都会当做一个bcc...

    写+调了4个多小时…6.5kb...到半夜12:15,然后今天11点才起床没去上学2333

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <map>
    using namespace std;
    typedef long long ll;
    #define fir first
    #define sec second
    const int N = 2e5+5, inf = 1e9+5;
    inline int read() {
        char c=getchar(); int x=0,f=1;
        while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    int n, m, Q, w[N], x, y, lim;
    char s[N];
    struct meow {int u, v;} g[N];
    
    namespace ufs {
    	int fa[N];
    	int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
    } using ufs::find;
    
    struct edge {int v, ne;} e[N<<1];
    int cnt, h[N];
    map<int, int> has[N];
    inline void ins(int u, int v) {
        if(has[u][v]) return; has[u][v] = 1;
        if(find(u) == find(v)) return;
        //printf("ins %d %d
    ", u, v);
    	ufs::fa[find(u)] = find(v);
    	e[++cnt] = (edge) {v, h[u]}; h[u] = cnt;
    	e[++cnt] = (edge) {u, h[v]}; h[v] = cnt;
    }
    inline void link(int u, int v) {ins(u, v);}
    namespace G {
    	struct edge {int v, ne;} e[N<<1];
    	int cnt, h[N];
    	inline void ins(int u, int v) {
    		e[++cnt] = (edge) {v, h[u]}; h[u] = cnt;
    		e[++cnt] = (edge) {u, h[v]}; h[v] = cnt;
    	}
    	int dfn[N], low[N], dfc, is_cut[N], bel[N], bcc, bcc_size[N];
    	struct meow {int u, v;} st[N]; int top;
    	void dfs(int u, int fa) {
    		dfn[u] = low[u] = ++dfc;
    		int child = 0;
    		for(int i=h[u]; i; i=e[i].ne) {
    			int v = e[i].v;
    			if(v == fa) continue;
    			meow cur_edge = (meow){u, v};
    			if(!dfn[v]) {
    				st[++top] = cur_edge;
    				child++;
    				dfs(v, u);
    				low[u] = min(low[u], low[v]);
    				if(low[v] >= dfn[u]) {
    					is_cut[u] = true;
    					bcc++;
    					while(true) {
    						meow x = st[top--];
    						if(bel[x.u] != bcc) {
                                bel[x.u] = bcc, bcc_size[bcc]++;
                                if(is_cut[x.u]) link(n+bcc, x.u);
                            }
    						if(bel[x.v] != bcc) {
                                bel[x.v] = bcc, bcc_size[bcc]++;
                                if(is_cut[x.v]) link(n+bcc, x.v);
                            }
    						if(x.u == u && x.v == v) break;
    					}
    				}
    			} else if(dfn[v] < dfn[u]) st[++top] = cur_edge, low[u] = min(low[u], dfn[v]);
    		}
    		if(fa == 0 && child == 1) is_cut[u] = false;
    	}
    }
    using G::is_cut; using G::bcc; using G::bel; using G::bcc_size;
    
    
    int root, no_cut = 1;
    multiset<int> q[N];
    
    void build_tree() {
    
    	//for(int i=1; i<=n<<1; i++) if(is_cut[i]) printf("cut %d
    ", i);
        for(int i=1; i<=n; i++) bel[i] += n;// printf("bel %d  %d
    ", i, bel[i]);
        using G::e; using G::h;
        for(int u=1; u<=n; u++) {
            if(is_cut[u]) {
                for(int i=h[u]; i; i=e[i].ne) {
                    int v = e[i].v;
                    if(!is_cut[v]) ins(bel[v], u);
                }
            } else q[bel[u]].insert(w[u]);// printf("insert %d  %d %d
    ", u, bel[u], w[u]);
        }
    	for(int i=1; i<=m; i++) {
    		int u = g[i].u, v = g[i].v; //printf("(%d, %d)   %d  %d
    ", u, v, find(u), find(v));
    		if(is_cut[u] && is_cut[v] && find(u) != find(v)) ins(u, v);
    	}
    	if(is_cut[1]) root = 1;
    	else root = bel[1];
    	for(int i=1; i<=n; i++) if(is_cut[i]) no_cut = 0;
    }
    
    int dfn[N], dfc, deep[N], top[N], fa[N], size[N], mx[N];
    void dfs(int u) {
    	size[u] = 1;
    	for(int i=h[u]; i; i=e[i].ne) {
    		int v = e[i].v;
    		if(v == fa[u]) continue;
    		fa[v] = u;
    		deep[v] = deep[u] + 1;
    		if(!is_cut[u] && is_cut[v]) q[u].insert(w[v]);
    		dfs(v);
    		size[u] += size[v];
    		if(size[v] > size[mx[u]]) mx[u] = v;
    	}
    }
    int val[N];
    void dfs(int u, int anc) {
    	dfn[u] = ++dfc; val[dfc] = w[u];
    	top[u] = anc;
    	if(mx[u]) dfs(mx[u], anc);
    	for(int i=h[u]; i; i=e[i].ne) {
    		int v = e[i].v;
    		if(v != fa[u] && v != mx[u]) dfs(v, v);
    	}
    }
    
    namespace seg_t {
    	#define lc x<<1
    	#define rc x<<1|1
    	#define mid ((l+r)>>1)
    	#define lson lc, l, mid
    	#define rson rc, mid+1, r
    	int t[N<<2];
    	void build(int x, int l, int r) {
    		if(l == r) t[x] = val[l];
    		else {
    			build(lson);
    			build(rson);
    			t[x] = min(t[lc], t[rc]);
    		}
    	}
    	void cha(int x, int l, int r, int p, int v) {
    		if(l == r) t[x] = v;
    		else {
    			if(p <= mid) cha(lson, p, v);
    			else cha(rson, p, v);
    			t[x] = min(t[lc], t[rc]);
    		}
    	}
    	int que(int x, int l, int r, int ql, int qr) {
    		if(ql <= l && r <= qr) return t[x];
    		else {
    			int ans = inf;
    			if(ql <= mid) ans = min(ans, que(lson, ql, qr));
    			if(mid < qr)  ans = min(ans, que(rson, ql, qr));
    			return ans;
    		}
    	}
    } using seg_t::cha; using seg_t::que;
    
    void bcc_cha(int id, int u, int ww) {
    	q[id].erase(q[id].find(w[u]));
    	w[u] = ww;
    	q[id].insert(w[u]);
    	w[id] = *q[id].begin();
    	if(!no_cut) cha(1, 1, dfc, dfn[id], w[id]);
    }
    void bcc_cha2(int id, int last_w, int now_w) { //printf("bbc_cha2 %d  %d %d
    ", id, last_w, now_w);
    	q[id].erase(q[id].find(last_w));
    	q[id].insert(now_w);
        //for(set<int>::iterator it = q[id].begin(); it != q[id].end(); it++) printf("%d ", *it); printf("  q
    ");
    	w[id] = *q[id].begin();
    	cha(1, 1, dfc, dfn[id], w[id]);
    }
    
    void change(int u, int ww) {
    	if(is_cut[u]) {
    		int last_w = w[u];
    		w[u] = ww, cha(1, 1, dfc, dfn[u], ww);
    		int f = fa[u]; //printf("f %d
    ", f);
    		if(f && !is_cut[f]) bcc_cha2(f, last_w, ww);
    	} else bcc_cha(bel[u], u, ww);
    }
    
    void query(int x, int y) {
    	if(x == y) {printf("%d
    ", w[x]); return;}
    	if(!is_cut[x]) x = bel[x];
    	if(!is_cut[y]) y = bel[y];
    	//printf("query %d %d
    ", x, y);
    	int ans = inf;
    	while(top[x] != top[y]) {
    		if(deep[top[x]] < deep[top[y]]) swap(x, y);
    		ans = min(ans, que(1, 1, dfc, dfn[top[x]], dfn[x]));
    		x = fa[top[x]];
    	}
    	if(dfn[x] > dfn[y]) swap(x, y);
    	ans = min(ans, que(1, 1, dfc, dfn[x], dfn[y]));
    	if(!is_cut[x] && fa[x]) ans = min(ans, w[fa[x]]);
    	printf("%d
    ", ans);
    }
    
    int main() {
    	freopen("in", "r", stdin);
    	n = read(); m = read(); Q = read();
    	for(int i=1; i<=n; i++) w[i] = read();
    	for(int i=1; i<=m; i++) g[i].u = read(), g[i].v = read(), G::ins(g[i].u, g[i].v);
        for(int i=1; i<=n<<1; i++) ufs::fa[i] = i;
    
    	G::dfs(1, 0);
    	build_tree();
    	if(no_cut) {
            w[n+1] = *q[n+1].begin();
    		for(int i=1; i<=Q; i++) {
    			scanf("%s", s); x = read(); y = read();
    			if(s[0] == 'C') bcc_cha(n+1, x, y);
    			else printf("%d
    ", x==y ? w[x] : w[n+1]);
    		}
    		return 0;
    	}
    
    	dfs(root); dfs(root, root);
        for(int i=1; i<=bcc; i++) w[i+n] = *q[i+n].begin(), val[dfn[i+n]] = w[i+n];
    	seg_t::build(1, 1, dfc); //puts("hi");
    
    	for(int i=1; i<=Q; i++) { //printf("
    --------Q----------- %d
    ", i);
    		scanf("%s", s); x = read(); y = read();
    		if(s[0] == 'C') change(x, y);
    		else query(x, y);
    	}
    }
    
    
  • 相关阅读:
    jackson 枚举 enum json 解析类型 返回数字 或者自定义文字 How To Serialize Enums as JSON Objects with Jackson
    Antd Pro V5 中ProTable 自定义查询参数和返回值
    ES6/Antd 代码阅读记录
    es 在数据量很大的情况下(数十亿级别)如何提高查询效率啊?
    Antd Hooks
    使用.Net Core开发WPF App系列教程(其它 、保存控件内容为图片)
    使用.Net Core开发WPF App系列教程( 三、与.Net Framework的区别)
    使用.Net Core开发WPF App系列教程( 四、WPF中的XAML)
    使用.Net Core开发WPF App系列教程( 二、在Visual Studio 2019中创建.Net Core WPF工程)
    使用.Net Core开发WPF App系列教程( 一、.Net Core和WPF介绍)
  • 原文地址:https://www.cnblogs.com/candy99/p/6855859.html
Copyright © 2011-2022 走看看