zoukankan      html  css  js  c++  java
  • CodeForces 487E Tourists(圆方树+线段树+树链剖分)

    题意

    (n) 个点 (m) 条边的无向连通图,每个点有点权,(q) 个要求,每次更新一个点的点权或查询两点间路径权值最小的点最小的路径。

    思路

    ​ 算是圆方树的板子吧?圆方树处理的主要就是两点之间路径的问题。

    ​ 我们先对原图建一棵圆方树,然后每个圆点的信息传递给父亲,一定是方点,用堆维护信息。最后只要树剖线段树查路径最小值即可,注意特判 ( m{lca}) 即可。

    代码

    #include<bits/stdc++.h>
    #define FOR(i, x, y) for(int i = (x), i##END = (y); i <= i##END; ++i)
    #define DOR(i, x, y) for(int i = (x), i##END = (y); i >= i##END; --i)
    template<typename T, typename _T> inline bool chk_min(T &x, const _T &y) {return y < x ? x = y, 1 : 0;}
    template<typename T, typename _T> inline bool chk_max(T &x, const _T &y) {return x < y ? x = y, 1 : 0;}
    typedef long long ll;
    const int N = 100005;
    const int M = 100005;
    
    template<const int N, const int M, typename T> struct Linked_List
    {
    	int head[N], nxt[M], tot; T to[M];
    	Linked_List() {clear();}
    	T &operator [](const int x) {return to[x];}
    	void clear() {memset(head, -1, sizeof(head)), tot = 0;}
    	void add(int u, T v) {to[tot] = v, nxt[tot] = head[u], head[u] = tot++;}
    	#define EOR(i, G, u) for(int i = G.head[u]; ~i; i = G.nxt[i])
    };
    
    
    struct Segment_Tree
    {
    	int mi[N << 3];
    	void update(int k, int x, int val, int l, int r)
    	{
    		if(l == r) {mi[k] = val; return;}
    		int mid = (l + r) >> 1;
    		if(x <= mid) update(k << 1, x, val, l, mid);
    		else update(k << 1 | 1, x, val, mid + 1, r);
    		mi[k] = std::min(mi[k << 1], mi[k << 1 | 1]);
    	}
    	int query(int k, int L, int R, int l, int r)
    	{
    		if(L <= l && r <= R) return mi[k];
    		int mid = (l + r) >> 1;
    		if(R <= mid) return query(k << 1, L, R, l, mid);
    		else if(L > mid) return query(k << 1 | 1, L, R, mid + 1, r);
    		else return std::min(query(k << 1, L, R, l, mid), query(k << 1 | 1, L, R, mid + 1, r));
    	}
    };
    
    Linked_List<N, M << 1, int> G;
    Linked_List<N << 1, N << 2, int> T;
    Segment_Tree ST;
    
    int dfn[N], low[N], stk[N], idxer, bcc, tp;
    
    int fa[N << 1], dep[N << 1], sz[N << 1], son[N << 1], top[N << 1];
    int lfn[N << 1], rfn[N << 1], ori[N << 1], dfn_idx;
    int pw[N << 1];
    std::multiset<int> st[N << 1];
    
    int n, m, q;
    
    void tarjan(int u, int fa_e)
    {
    	dfn[u] = low[u] = ++idxer;
    	stk[++tp] = u;
    
    	EOR(i, G, u)
    	{
    		if(i == (fa_e ^ 1)) continue;
    		int v = G[i];
    		if(!dfn[v])
    		{
    			tarjan(v, i), chk_min(low[u], low[v]);
    			if(low[v] >= dfn[u])
    			{
    				bcc++;
    				do
    				{
    					T.add(n + bcc, stk[tp]);
    					T.add(stk[tp], n + bcc);
    				}
    				while(stk[tp--] != v);
    				T.add(n + bcc, u), T.add(u, n + bcc);
    			}
    		}
    		else if(dfn[v] < dfn[u])
    			chk_min(low[u], dfn[v]);
    	}
    }
    
    void dfs(int u, int f, int d)
    {
    	fa[u] = f, dep[u] = d, sz[u] = 1, son[u] = 0;
    	EOR(i, T, u)
    	{
    		int v = T[i];
    		if(v == f) continue;
    		dfs(v, u, d + 1);
    		sz[u] += sz[v];
    		if(sz[v] > sz[son[u]]) son[u] = v;
    	}
    }
    
    void hld(int u, int tp)
    {
    	ori[lfn[u] = ++dfn_idx] = u;
    	top[u] = tp;
    	if(son[u]) hld(son[u], tp);
    	EOR(i, T, u)
    	{
    		int v = T[i];
    		if(v == fa[u] || v == son[u]) continue;
    		hld(v, v);
    	}
    	rfn[u] = dfn_idx;
    }
    
    int get_lca(int u, int v)
    {
    	while(top[u] != top[v])
    	{
    		if(dep[top[u]] < dep[top[v]]) std::swap(u, v);
    		u = fa[top[u]];
    	}
    	return dep[u] < dep[v] ? u : v;
    }
    
    int query(int u, int v)
    {
    	int res = 2e9;
    	while(top[u] != top[v])
    	{
    		if(dep[top[u]] < dep[top[v]]) std::swap(u, v);
    		chk_min(res, ST.query(1, lfn[top[u]], lfn[u], 1, n + bcc));
    		u = fa[top[u]];
    	}
    	if(dep[u] > dep[v]) std::swap(u, v);
    	chk_min(res, ST.query(1, lfn[u], lfn[v], 1, n + bcc));
    	if(u > n) chk_min(res, pw[fa[u]]);
    	return res;
    }
    
    int main()
    {
    	scanf("%d%d%d", &n, &m, &q);
    	FOR(i, 1, n) scanf("%d", &pw[i]);
    	FOR(i, 1, m)
    	{
    		int u, v;
    		scanf("%d%d", &u, &v);
    		G.add(u, v), G.add(v, u);
    	}
    
    	tarjan(1, -1);
    	dfs(1, 0, 1), hld(1, 1);
    
    	FOR(u, n + 1, n + bcc)
    	{
    		EOR(i, T, u)
    		{
    			int v = T[i];
    			if(v == fa[u]) continue;
    			st[u].insert(pw[v]);
    		}
    		pw[u] = (*st[u].begin());
    	}
    	
    	FOR(i, 1, n + bcc) ST.update(1, lfn[i], pw[i], 1, n + bcc);
    
    	while(q--)
    	{
    		char str[3]; int a, b;
    		scanf("%s%d%d", str, &a, &b);
    		if(str[0] == 'C')
    		{
    			if(fa[a])
    			{
    				st[fa[a]].erase(st[fa[a]].find(pw[a]));
    				st[fa[a]].insert(b);
    				pw[fa[a]] = (*st[fa[a]].begin());
    				ST.update(1, lfn[fa[a]], pw[fa[a]], 1, n + bcc);
    			}
    			pw[a] = b;
    			ST.update(1, lfn[a], b, 1, n + bcc);
    			
    		}
    		else if(str[0] == 'A')
    			printf("%d
    ", query(a, b));
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    第六章 类(Class) 和对象(Object)
    如何在windows Server 2008虚拟机上安装SQLServer2008数据库
    小票打印机乱码问题
    SQLSERVER 的联接查询写法
    VMware下安装CentOS6.5
    疯狂java讲义--笔记
    学习Java第一篇——Java 安装及环境搭配
    informix数据迁移工具使用介绍
    informix 存储过程结构
    输入身份证号码自动读取生日与性别(delphi)
  • 原文地址:https://www.cnblogs.com/Paulliant/p/12069568.html
Copyright © 2011-2022 走看看