Submission #1119748

#TimeUsernameProblemLanguageResultExecution timeMemory
1119748RequiemSynchronization (JOI13_synchronization)C++17
100 / 100
619 ms40776 KiB
#include<bits/stdc++.h>
#define int long long
#define pb push_back
#define fast ios_base::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
#define MOD 1000000007
#define inf 1e18
#define fi first
#define se second
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define FORD(i,a,b) for(int i=a;i>=b;i--)
#define sz(a) ((int)(a).size())
#define endl '\n'
#define pi 3.14159265359
#define TASKNAME "synchronization"
using namespace std;
template<typename T> bool maximize(T &res, const T &val) { if (res < val){ res = val; return true; }; return false; }
template<typename T> bool minimize(T &res, const T &val) { if (res > val){ res = val; return true; }; return false; }
typedef pair<int,int> ii;
typedef pair<int,ii> iii;
typedef vector<int> vi;

/**
Cho 1 cây N đỉnh.

Ta có các thao tác, bật tắt cạnh.

Ta có q truy vấn:
- với đỉnh u, hãy đếm số đỉnh từng cùng thành phần liên thông với u.

Bài này dùng observation:

Khi ta thêm 1 cạnh (u, v) vào kết quả của thành phần liên thông sẽ trở thành:

ans_new = ans[u] + ans[v] - c. c: số thằng mà 2 thằng giống nhau.

Trong đó c là kết quả của lần kết hợp gần nhất (c = 0, nếu chưa từng kết hợp)

Nhưng ta không thể lưu kết quả cho tất cả các nút được nên ta
sẽ lấy 1 nút làm đại diện (nút có độ cao thấp nhất trên cây
**/

struct BinaryIndexedTree{
    vector<int> BIT;
    BinaryIndexedTree(int sz = 0){
        BIT.resize(sz + 9);
    }

    int get(int id){
        int res = 0;
        for(int i = id; i > 0; i -= i & (-i)){
            res += BIT[i];
        }
        return res;
    }

    void update(int id, int x){
        for(int i = id; i < BIT.size(); i += i & (-i)){
            BIT[i] += x;
        }
    }
};

const int MAXN = 3e5 + 9;
vector<int> g[MAXN];
ii edge[MAXN];

int n, m, q;

BinaryIndexedTree opt;
int dfsTime = 0;
int del[MAXN], in[MAXN], out[MAXN], depth[MAXN], P[30][MAXN];

int ans[MAXN], ans_edge_before[MAXN];

void dfs(int u, int p){
    P[0][u] = p;
    in[u] = ++dfsTime;
    for(auto id: g[u]){
        int v = edge[id].se + edge[id].fi - u;
        if (v == p) continue;
        depth[v] = depth[u] + 1;
        dfs(v, u);
    }
    out[u] = dfsTime;
}

int jumpKth(int u, int k){
    for(int i = 0; k > 0; k >>= 1, i++){
        if (k&1) u = P[i][u];
    }
    return u;
}

int root(int u){
    int s = opt.get(in[u]);

    int l = 0, r = depth[u], res = 0;

    while(l <= r){
        int mid = (l + r) >> 1;
        if (opt.get(in[ jumpKth(u, mid) ]) == s){
            res = mid;
            l = mid + 1;
        }
        else{
            r = mid - 1;
        }
    }

    return jumpKth(u, res);
}

void eraseEdge(int u){
    opt.update(in[u], 1);
    opt.update(out[u] + 1, -1);
}

void addEdge(int u){
    opt.update(in[u], -1);
    opt.update(out[u] + 1, 1);
}
void updateEdge(int id){
    int u = edge[id].se;
    int p = root(edge[id].fi);

    if (del[id] == 0){
        del[id] = 1;
        ans[u] = ans[p];
        ans_edge_before[id] = ans[p];
    }
    else{
        ans[p] = ans[u] + ans[p] - ans_edge_before[id];
        del[id] = 0;
    }

    if (del[id] == 1) eraseEdge(u);
    else addEdge(u);
}

main()
{
    fast;
    if (fopen(TASKNAME".inp","r")){
        freopen(TASKNAME".inp","r",stdin);
        freopen(TASKNAME".out","w",stdout);
    }
    cin >> n >> m >> q;
    FOR(i, 1, n - 1){
        int u, v;
        cin >> u >> v;
        edge[i] = {u, v};
        g[u].pb(i);
        g[v].pb(i);
    }

    fill(del, del + 1 + n, 1);
    dfs(1, -1);

    FOR(i, 1, 20){
        FOR(j, 1, n){
            if (P[i - 1][j] == -1) P[i][j] = -1;
            else P[i][j] = P[i - 1][P[i - 1][j]];
        }
    }

    FOR(i, 1, n - 1){
        if (depth[edge[i].fi] > depth[edge[i].se]) swap(edge[i].fi, edge[i].se);
    }

    opt = BinaryIndexedTree(n + 1);

    FOR(i, 1, n){
        eraseEdge(i);
        ans[i] = 1;
    }

    FOR(i, 1, m){
        int u;
        cin >> u;
        updateEdge(u);

    }

    FOR(i, 1, q){
        int u;
        cin >> u;
        cout << ans[root(u)] << endl;
    }
}
/**
Warning:
Đọc sai đề???
Cận lmao
Code imple thiếu case nào không.
Limit.
**/

Compilation message (stderr)

synchronization.cpp: In member function 'void BinaryIndexedTree::update(long long int, long long int)':
synchronization.cpp:57:27: warning: comparison of integer expressions of different signedness: 'long long int' and 'std::vector<long long int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
   57 |         for(int i = id; i < BIT.size(); i += i & (-i)){
      |                         ~~^~~~~~~~~~~~
synchronization.cpp: At global scope:
synchronization.cpp:140:1: warning: ISO C++ forbids declaration of 'main' with no type [-Wreturn-type]
  140 | main()
      | ^~~~
synchronization.cpp: In function 'int main()':
synchronization.cpp:144:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  144 |         freopen(TASKNAME".inp","r",stdin);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
synchronization.cpp:145:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  145 |         freopen(TASKNAME".out","w",stdout);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
#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...