codeforcesnode
UOJios
这个问题要是放到树上就很好作了,那能不能把它等效到一棵树上呢?固然是能够的数组
注意到“不通过重复的城市”,显然若是一条路径通过一个点双联通份量,那么点双中的全部点均可以通过ui
点双??因而套路上圆方树,询问显然能够方便地树链剖分解决,主要问题在于修改spa
圆方树自己是无根树,为了方便树链剖分,咱们会选一个点作树根,不妨就选个圆点code
而后发现一个方点的信息就是它的一堆儿子和一个父亲的信息内存
父亲只有一个,咱们彻底能够询问到的时候再处理父亲get
而后能够用一个\(multiset\)存下全部儿子的信息string
这样每次修改咱们只用修改它本身的信息和它父亲的信息it
询问依然采用树链剖分,当\(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\n", 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