Submission #402713

#TimeUsernameProblemLanguageResultExecution timeMemory
402713thuanqvbn03Bridges (APIO19_bridges)C++17
100 / 100
2062 ms9828 KiB
//Flower_On_Stone
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 100005;
const int BLOCK = 400;

struct Edge
{
    int u, v, w;
};

struct Query
{
    int type, u, v, id;
};

struct DisjointSetWithRollback
{
    struct DisjointSetSave
    {
        int u, rankU, sizeConnectedU, v, rankV, sizeConnectedV;
        DisjointSetSave(int _u = 0, int _rankU = 0, int _sizeConnectedU = 0, int _v = 0, int _rankV = 0, int _sizeConnectedV = 0) : u(_u), rankU(_rankU), sizeConnectedU(_sizeConnectedU), v(_v), rankV(_rankV), sizeConnectedV(_sizeConnectedV) {}
    };
    int numNode;
    int parent[MAX_N], rank[MAX_N], sizeConnected[MAX_N];
    stack<DisjointSetSave> s;
    void init(int numNode)
    {
        this->numNode = numNode;
        for (int node = 1; node <= numNode; node++)
        {
            parent[node] = node;
            rank[node] = 0;
            sizeConnected[node] = 1;
        }
        while (s.size())
        {
            s.pop();
        }
    }
    int findRoot(int node) { return (node == parent[node] ? node : findRoot(parent[node])); }
    bool join(int u, int v)
    {
        u = findRoot(u);
        v = findRoot(v);
        if (u == v)
        {
            return false;
        }
        if (rank[u] < rank[v])
        {
            swap(u, v);
        }
        s.push(DisjointSetSave(u, rank[u], sizeConnected[u], v, rank[v], sizeConnected[v]));
        parent[v] = u;
        sizeConnected[u] += sizeConnected[v];
        if (rank[u] == rank[v])
        {
            rank[u]++;
        }
        return true;
    }
    void rollback()
    {
        if (s.empty())
        {
            return;
        }
        DisjointSetSave dsuSave = s.top();
        s.pop();
        parent[dsuSave.u] = dsuSave.u;
        rank[dsuSave.u] = dsuSave.rankU;
        sizeConnected[dsuSave.u] = dsuSave.sizeConnectedU;
        parent[dsuSave.v] = dsuSave.v;
        rank[dsuSave.v] = dsuSave.rankV;
        sizeConnected[dsuSave.v] = dsuSave.sizeConnectedV;
    }
    int getSizeConnected(int node)
    {
        return sizeConnected[findRoot(node)];
    }
} dsuRollback;

int numTest, numNode, numEdge, numQuery;
Edge edges[MAX_N];
int edgesId[MAX_N];
Query query[MAX_N], tmpQuery[BLOCK];
vector<pair<int, int>> change[MAX_N];
bool haveChange[MAX_N];
vector<int> edgesChange;
int answer[MAX_N];

void solve(int left, int right)
{
    edgesChange.clear();
    int cntQuery = 0;
    for (int i = left; i <= right; i++)
    {
        if (query[i].type == 2)
        {
            tmpQuery[++cntQuery] = query[i];
        }
        else
        {
            if (!haveChange[query[i].u])
            {
                haveChange[query[i].u] = true;
                edgesChange.push_back(query[i].u);
                change[query[i].u].push_back(make_pair(left - 1, edges[query[i].u].w));
            }
            change[query[i].u].push_back(make_pair(i, query[i].v));
        }
    }
    int cntEdge = 0;
    for (int i = 1; i <= numEdge; i++)
    {
        if (!haveChange[edgesId[i]])
        {
            edgesId[++cntEdge] = edgesId[i];
        }
    }
    sort(tmpQuery + 1, tmpQuery + cntQuery + 1, [&](const Query &a, const Query &b)
         { return a.v > b.v; });
    dsuRollback.init(numNode);
    int j = 1;
    for (int i = 1; i <= cntQuery; i++)
    {
        while (j <= cntEdge && edges[edgesId[j]].w >= tmpQuery[i].v)
        {
            dsuRollback.join(edges[edgesId[j]].u, edges[edgesId[j]].v);
            j++;
        }
        int cnt = 0;
        for (auto &id : edgesChange)
        {
            auto it = lower_bound(change[id].begin(), change[id].end(), make_pair(tmpQuery[i].id, 0));
            it--;
            if (it->second >= tmpQuery[i].v)
            {
                cnt += dsuRollback.join(edges[id].u, edges[id].v);
            }
        }
        answer[tmpQuery[i].id] = dsuRollback.getSizeConnected(tmpQuery[i].u);
        while (cnt--)
        {
            dsuRollback.rollback();
        }
    }
    for (auto &x : edgesChange)
    {
        edges[x].w = change[x].back().second;
        haveChange[x] = false;
        change[x].clear();
    }
    sort(edgesChange.begin(), edgesChange.end(), [&](const int &x, const int &y)
         { return edges[x].w > edges[y].w; });
    int pos = numEdge;
    while (edgesChange.size())
    {
        if (cntEdge == 0)
        {
            edgesId[pos--] = edgesChange.back();
            edgesChange.pop_back();
            continue;
        }
        if (edges[edgesChange.back()].w <= edges[edgesId[cntEdge]].w)
        {
            edgesId[pos--] = edgesChange.back();
            edgesChange.pop_back();
        }
        else
        {
            edgesId[pos--] = edgesId[cntEdge];
            cntEdge--;
        }
    }
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef Flower_On_Stone
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif // Flower_On_Stone
    {
        cin >> numNode >> numEdge;
        for (int i = 1; i <= numEdge; i++)
        {
            cin >> edges[i].u >> edges[i].v >> edges[i].w;
            edgesId[i] = i;
        }
        sort(edgesId + 1, edgesId + numEdge + 1, [&](const int &x, const int &y)
             { return edges[x].w > edges[y].w; });
        cin >> numQuery;
        for (int i = 1; i <= numQuery; i++)
        {
            cin >> query[i].type >> query[i].u >> query[i].v;
            query[i].id = i;
        }
        for (int i = 1; i <= numQuery; i += BLOCK)
        {
            solve(i, min(numQuery, i + BLOCK - 1));
        }
        for (int i = 1; i <= numQuery; i++)
        {
            if (query[i].type == 2)
            {
                cout << answer[i] << '\n';
            }
        }
    }
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...