Monday, December 10, 2018

[Codeforces] E. Tourists

Author            : Dipu Kumar Mohanto 
                    CSE, Batch - 6
                    BRUR.
Problem Statement : E. Tourists
Source            : Codeforces
Category          : Graph Theory
Algorithm         : Block Cut Tree, Heavy Light Decomposition, Segment Tree
Verdict           : Accepted
#include "bits/stdc++.h"
 
using namespace std;
 
#define em             emplace
#define eb             emplace_back
#define sz(a)          a.size()
#define vi             vector <int>
 
inline int read()      { int a; scanf("%d", &a); return a; }
 
static const int maxn = 2e5 + 5;
static const int logn = 19;
 
vi graph[maxn], btree[maxn];
stack <int> s;
multiset <int> ord[maxn];
int tnode, tedge, tquery;
int dfsTime, disc[maxn], low[maxn], tot, bcc[maxn], w[maxn];
 
void addEdge1(int u, int v)
{
    graph[u].eb(v);
    graph[v].eb(u);
}
 
void addEdge2(int u, int v)
{
    btree[u].eb(v);
    btree[v].eb(u);
}
 
void findBCC(int u = 1, int p = -1)
{
    dfsTime++;
    disc[u] = low[u] = dfsTime;
    s.emplace(u);
    for (int v : graph[u])
    {
        if (v == p) continue;
        if (!disc[v])
        {
            findBCC(v, u);
            low[u] = min(low[u], low[v]);
            if (disc[u] <= low[v])
            {
                tot++;
                int h;
                do {
                    h = s.top();
                    addEdge2(h, tot);
                    bcc[h] = tot;
                    ord[tot].em(w[h]);
                    s.pop();
                } while (h != v);
                addEdge2(tot, u);
            }
        }
        else
        {
            low[u] = min(low[u], disc[v]);
        }
    }
}
 
int subTreeSize[maxn], father[maxn][logn], depth[maxn];
 
void dfs(int u = 1, int p = -1)
{
    for (int i = 1; i < logn; i++) father[u][i] = father[ father[u][i-1] ][i-1];
    subTreeSize[u] = 1;
    for (int v : btree[u])
    {
        if (v == p) continue;
        depth[v] = depth[u] + 1;
        father[v][0] = u;
        dfs(v, u);
        subTreeSize[u] += subTreeSize[v];
    }
}
 
int findLCA(int u, int v)
{
    if (depth[u] < depth[v]) swap(u, v);
    for (int i = logn-1; i >= 0; i--) if (depth[ father[u][i] ] >= depth[v]) u = father[u][i];
    if (u == v) return u;
    for (int i = logn-1; i >= 0; i--) if (father[u][i] != father[v][i]) u = father[u][i], v = father[v][i];
    return father[u][0];
}
 
int chainNo, chainHead[maxn], chainInd[maxn], chainPos[maxn], chainSize[maxn],
    baseArray[maxn], posBase[maxn], ptr, S, E;
 
void hld(int u = 1, int p = -1)
{
    if (chainHead[chainNo] == -1) chainHead[chainNo] = u;
    chainInd[u] = chainNo;
    ptr++;
    baseArray[ptr] = w[u];
    posBase[u] = ptr;
    int specialChild = -1;
    int maxSize = -1;
    for (int v : btree[u])
    {
        if (v == p) continue;
        if (subTreeSize[v] > maxSize) maxSize = subTreeSize[v], specialChild = v;
    }
    if (specialChild != -1) hld(specialChild, u);
    for (int v : btree[u])
    {
        if (v == p) continue;
        if (v != specialChild) chainNo++, hld(v, u);
    }
}
 
struct segmentTree
{
    int minValue;
    void assignLeaf(int val)
    {
        minValue = val;
    }
    void marge(segmentTree &l, segmentTree &r)
    {
        if (l.minValue == -1) minValue = r.minValue;
        else if (r.minValue == -1) minValue = l.minValue;
        else minValue = min(l.minValue, r.minValue);
    }
    int getRes()
    {
        return minValue;
    }
} TREE[maxn << 2];
 
void update(int node, int a, int b, int pos, int value)
{
    if (a > b || a > pos || b < pos) return;
    if (a >= pos && b <= pos)
    {
        TREE[node].assignLeaf(value);
        return;
    }
    int left = node << 1;
    int right = left | 1;
    int mid = (a + b) >> 1;
    update(left, a, mid, pos, value);
    update(right, mid+1, b, pos, value);
    TREE[node].marge(TREE[left], TREE[right]);
}
 
segmentTree query(int node, int a, int b, int i, int j)
{
    if (a > b || a > j || b < i) return {-1};
    if (a >= i && b <= j) return TREE[node];
    int left = node << 1;
    int right = left | 1;
    int mid = (a + b) >> 1;
    segmentTree p1, p2, res;
    p1 = query(left, a, mid, i, j);
    p2 = query(right, mid+1, b, i, j);
    res.marge(p1, p2);
    return res;
}
 
void changeNodeCost(int u, int value)
{
    int pos = posBase[u];
    update(1, S, E, pos, value);
}
 
int queryUp(int u, int v)
{
    // u -> always the lowest node, v -> lca
    int uChain, vChain = chainInd[v], minValue = INT_MAX;
    while (true)
    {
        uChain = chainInd[u];
        if (uChain == vChain)
        {
            int l = posBase[v];
            int r = posBase[u];
            if (l > r) break;
            int ans = query(1, S, E, l, r).getRes();
            if (ans < minValue) minValue = ans;
            break;
        }
        int l = posBase[ chainHead[uChain] ];
        int r = posBase[u];
        int ans = query(1, S, E, l, r).getRes();
        if (ans < minValue) minValue = ans;
        u = father[ chainHead[uChain] ][0];
    }
    return minValue;
}
 
int queryHLD(int u, int v)
{
    int lca = findLCA(u, v); // ok
    int minValue = queryUp(u, lca);
    minValue = min(minValue, queryUp(v, lca));
    if (lca > tnode) minValue = min(minValue, queryUp(lca, father[lca][0]));
    return minValue;
}
 
void init()
{
    ptr = 0;
    chainNo = 0;
    for (int i = 0; i < maxn; i++)
    {
        graph[i].clear();
        btree[i].clear();
        bcc[i] = 0;
        subTreeSize[i] = 0;
        chainHead[i] = -1;
        chainInd[i] = 0;
        depth[i] = 0;
        baseArray[i] = 0;
        posBase[i] = 0;
        bcc[i] = 0;
        for (int j = 0; j < logn; j++) father[i][j] = 0;
    }
}
 
int main()
{
//    freopen("in.txt", "r", stdin);
 
    init();
    tnode = read(), tedge = read(), tquery = read();
    for (int i = 1; i <= tnode; i++) w[i] = read();
    for (int e = 1; e <= tedge; e++)
    {
        int u = read(), v = read();
        addEdge1(u, v);
    }
    tot = tnode; // must
    findBCC();
    depth[1] = 1;
    dfs();
    hld();
    S = 1;
    E = ptr;
    for (int i = 1; i <= tnode; i++) changeNodeCost(i, w[i]);
    for (int i = tnode+1; i <= tot; i++) changeNodeCost(i, *ord[i].begin());
    char t;
    while (tquery--)
    {
        int u, v;
        scanf("\n%c %d %d", &t, &u, &v);
        if (t == 'C')
        {
            changeNodeCost(u, v);
            if (bcc[u])
            {
                int bccno = bcc[u];
                ord[bccno].erase(ord[bccno].find(w[u]));
                ord[bccno].em(v);
                changeNodeCost(bccno, *ord[bccno].begin());
            }
            w[u] = v;
        }
        else printf("%d\n", queryHLD(u, v));
    }
}
 

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.