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