zoukankan      html  css  js  c++  java
  • UOJ#30[Codeforces 487E]Tourists(圆方树+树链剖分)

    题目链接

    codeforces

    UOJ

    解析

    这个问题要是放到树上就很好做了,那能不能把它等效到一棵树上呢?当然是可以的

    注意到“不经过重复的城市”,显然如果一条路径经过一个点双联通分量,那么点双中的所有点都可以经过

    点双??于是套路上圆方树,询问显然可以方便地树链剖分解决,主要问题在于修改

    圆方树本身是无根树,为了方便树链剖分,我们会选一个点做树根,不妨就选个圆点

    然后发现一个方点的信息就是它的一堆儿子和一个父亲的信息

    父亲只有一个,我们完全可以询问到的时候再处理父亲

    然后可以用一个(multiset)存下所有儿子的信息

    这样每次修改我们只用修改它自己的信息和它父亲的信息

    询问依然采用树链剖分,当(LCA)是方点的时候单独查一下父亲的信息即可

    代码

    自带大常数,(UOJ 7600ms)

    话说为什么(UOJ)(CF)数组越界都是(MLE),害我卡了半下午内存……

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <set>
    #define MAXN 100005
    
    typedef long long LL;
    const int inf = 0x3f3f3f3f;
    struct Graph {
    	struct Edge {
    		int v, next;
    		Edge(int _v = 0, int _n = 0):v(_v), next(_n) {}
    	} edge[MAXN << 2];
    	int head[MAXN << 1], cnt;
    	void init() { memset(head, -1, sizeof head); cnt = 0; }
    	void add_edge(int u, int v) { edge[cnt] = Edge(v, head[u]); head[u] = cnt++; }
    	void insert(int u, int v) { add_edge(u, v); add_edge(v, u); }
    };
    struct SegmentTree {
    	int data[MAXN << 3];
    	void build(int, int, int);
    	void update(int, int, int, int, int);
    	int query(int, int, int, int, int);
    };
    
    void Tarjan(int, int);
    void dfs1(int);
    void dfs2(int);
    
    int N, M, Q, w[MAXN], dfn[MAXN << 1], low[MAXN], idx, tot;
    int fa[MAXN << 1], top[MAXN << 1], size[MAXN << 1], pre[MAXN << 1], dep[MAXN << 1], heavy[MAXN << 1];
    int stk[MAXN], stop;
    SegmentTree sgt;
    Graph G, T;
    std::multiset<int> sqrnode[MAXN];
    
    int main() {
    	G.init(), T.init();
    	scanf("%d%d%d", &N, &M, &Q);
    	tot = N;
    	for (int i = 1; i <= N; ++i) scanf("%d", w + i);
    	for (int i = 1; i <= M; ++i) {
    		int u, v; scanf("%d%d", &u, &v);
    		G.insert(u, v);
    	}
    	Tarjan(1, 0);
    	dfs1(1);
    	idx = 0, top[1] = 1;
    	dfs2(1);
    	sgt.build(1, 1, tot);
    	while (Q--) {
    		char s[3]; int a, b;
    		scanf("%s%d%d", s, &a, &b);
    		if (s[0] == 'C') {
    			sgt.update(1, 1, tot, dfn[a], b);
    			if (fa[a]) {
    				sqrnode[fa[a] - N].erase(sqrnode[fa[a] - N].find(w[a]));
    				sqrnode[fa[a] - N].insert(b);
    				sgt.update(1, 1, tot, dfn[fa[a]], *sqrnode[fa[a] - N].begin());
    			}
    			w[a] = b;
    		} else {
    			int ans = inf;
    			while (top[a] ^ top[b]) {
    				if (dep[top[a]] < dep[top[b]]) std::swap(a, b);
    				ans = std::min(ans, sgt.query(1, 1, tot, dfn[top[a]], dfn[a]));
    				a = fa[top[a]];
    			}
    			if (dep[a] > dep[b]) std::swap(a, b);
    			ans = std::min(ans, sgt.query(1, 1, tot, dfn[a], dfn[b]));
    			if (fa[a] && fa[a] <= N) ans = std::min(ans, w[fa[a]]);
    			printf("%d
    ", ans);
    		}
    	}
    
    	return 0;
    }
    void Tarjan(int u, int fa) {
    	dfn[u] = low[u] = ++idx;
    	for (int i = G.head[u]; ~i; i = G.edge[i].next) {
    		int v = G.edge[i].v;
    		if (v == fa) continue;
    		if (!dfn[v]) {
    			stk[stop++] = v;
    			Tarjan(v, u);
    			low[u] = std::min(low[u], low[v]);
    			if (low[v] >= dfn[u]) {
    				int p; ++tot;
    				do {
    					p = stk[--stop];
    					T.insert(p, tot);
    				} while (p ^ v);
    				T.insert(u, tot);
    			}
    		} else low[u] = std::min(low[u], dfn[v]);
    	}
    }
    void dfs1(int u) {
    	dep[u] = dep[fa[u]] + 1;
    	size[u] = 1;
    	for (int i = T.head[u]; ~i; i = T.edge[i].next) {
    		int v = T.edge[i].v;
    		if (v ^ fa[u]) {
    			fa[v] = u, dfs1(v);
    			size[u] += size[v];
    			if (!heavy[u] || size[v] > size[heavy[u]]) heavy[u] = v;
    			if (u > N) sqrnode[u - N].insert(w[v]);
    		}
    	}
    }
    void dfs2(int u) {
    	dfn[u] = ++idx, pre[idx] = u;
    	if (heavy[u]) {
    		top[heavy[u]] = top[u];
    		dfs2(heavy[u]);
    	}
    	for (int i = T.head[u]; ~i; i = T.edge[i].next) {
    		int v = T.edge[i].v;
    		if ((v ^ fa[u]) && (v ^ heavy[u])) { top[v] = v; dfs2(v); }
    	}
    }
    void SegmentTree::build(int rt, int L, int R) {
    	if (L == R) data[rt] = (pre[L] <= N ? w[pre[L]] : *sqrnode[pre[L] - N].begin());
    	else {
    		int mid = (L + R) >> 1;
    		build(rt << 1, L, mid);
    		build(rt << 1 | 1, mid + 1, R);
    		data[rt] = std::min(data[rt << 1], data[rt << 1 | 1]);
    	}
    }
    void SegmentTree::update(int rt, int L, int R, int p, int v) {
    	if (L == R) data[rt] = v;
    	else {
    		int mid = (L + R) >> 1;
    		if (p <= mid) update(rt << 1, L, mid, p, v);
    		else update(rt << 1 | 1, mid + 1, R, p, v);
    		data[rt] = std::min(data[rt << 1], data[rt << 1 | 1]);
    	}
    }
    int SegmentTree::query(int rt, int L, int R, int l, int r) {
    	if (L >= l && R <= r) return data[rt];
    	int mid = (L + R) >> 1, res = inf;
    	if (l <= mid) res = std::min(res, query(rt << 1, L, mid, l, r));
    	if (r > mid) res = std::min(res, query(rt << 1 | 1, mid + 1, R, l, r));
    	return res;
    }
    //Rhein_E
    
    
  • 相关阅读:
    点击滚动到任意位置
    设置滚动条
    突破浏览器限制字体大小不能低于12px的限制
    font-family 字体及各大主流网站对比
    可视区尺寸改变的时候,重绘Echarts
    <input />
    switch (xx) { case xx: break ......}
    让页面随浏览器的窗口大小缩放而缩放
    对后端返回的 html 标签不识别的解决办法
    html 标签分类:块级元素、内联元素 ......
  • 原文地址:https://www.cnblogs.com/Rhein-E/p/10615569.html
Copyright © 2011-2022 走看看