Submission #1199236

#TimeUsernameProblemLanguageResultExecution timeMemory
1199236Ronin13JOI tour (JOI24_joitour)C++20
100 / 100
2215 ms307644 KiB
#include "joitour.h"
#include <bits/stdc++.h>
using ll = long long ;
using ull = unsigned ll;
#define f first 
#define s second 
#define pb push_back
#define epb emplace_back
using namespace std;
using pii = pair<int,int>;
using pll = pair<ll,ll>;

struct Data{

  vector <ll> f[3];
  int n;
  vector <ll> cnt;
  vector <vector<ll>>cnts;
  ll s_bad;
  Data() {
    cnt.resize(5);
  }
  void add(int pos, int val, int id) {
    while(pos < f[id].size()) {
      f[id][pos] += val;
      pos += (pos & -pos);
    }
  }
  ll get(int pos, int id) {
    ll res = 0;
    while(pos) {
      res += f[id][pos];
      pos -= (pos & -pos);
    }
    return res;
  }
  ll get(int l, int r, int id) {
    return get(r, id) - get(l - 1, id);
  }
};


const int nmax = 200001;
vector <vector <int>>vec(nmax);
vector <vector <int>>sz(nmax);
vector <vector<int>>in(nmax);
vector <vector <int>>g(nmax);
vector <int>y(nmax);
vector <vector<int>>lead_in(nmax);
Data dt[nmax];
vector <bool> blocked(nmax);
vector <int> siz(nmax);
ll ans;
int timer = 1;

vector <vector<ll>>cnt(nmax, vector<ll>(5));

void dfs(int v, int e) {
//  cout << v << ' ';
  siz[v] = 1;
  for(int to : g[v]) {
    if(to == e || blocked[to]) continue;
    dfs(to, v);
    siz[v] += siz[to];
  }
}

int find_cent(int v, int e, int n) {
  for(int to : g[v]) {
    if(blocked[to] || to == e) continue;
    if(siz[to] * 2 >= n) return find_cent(to, v, n);
  }
  return v;
}

void clear_dfs(int v, int e) {
  siz[v] = 0;
  for(int to : g[v]) {
    if(to == e || blocked[to]) continue;
    clear_dfs(to, v);
  }
  siz[v] = 0;
}


void update_cnt(int v, int to, bool x = false) {
  for(int i = 0; i < 5; i++) cnt[v][i] += cnt[to][i];
  if(y[v] == 1 && !x) {
    cnt[v][3] += cnt[to][0];
    cnt[v][4] += cnt[to][2];
  }
}

void DFS(int v, int e, int num, vector<int>&visited) {
    in[v].pb(timer++);
    lead_in[v].pb(num);
    sz[v].pb(1);
    visited.pb(v);
    for(int j = 0; j < 5; j++) cnt[v][j] = 0;
    for(int to : g[v]) {
      if(to == e || blocked[to]) continue;
      DFS(to, v, num, visited);
      update_cnt(v, to);
      sz[v].back() += sz[to].back();
    }
    cnt[v][y[v]]++;
}

void clearDFS(int v, int e) {
  cnt[v].assign(5, 0);
  for(int to : g[v]) {
    if(to == e || blocked[to]) continue;
    clearDFS(to, v);
  }
}

void decompose(int v) {
  dfs(v, v);
  int n = siz[v];
  int x = find_cent(v, v, siz[v]);

  clear_dfs(v, v);
  timer = 1;
  sz[x].pb(n);
  in[x].pb(1);
  vec[x].pb(x);
  lead_in[x].pb(0);
  int num = 0;
  vector <int> visited;
  for(int to : g[x]) {
    if(blocked[to]) continue;
    DFS(to, x, num, visited);
    update_cnt(x, to, true);
    dt[x].cnts.pb(cnt[to]);
    dt[x].s_bad += cnt[to][2] * cnt[to][0];
    num++;
  }

  cnt[x][y[x]]++;
  for(int j = 0; j< 3; j++) {
    dt[x].f[j].resize(n + 1);
  }
  dt[x].cnt = cnt[x];
  for(auto to : visited) {
    vec[to].pb(x);
    if(y[to] != 1) {
      dt[x].add(in[to].back(), 1, y[to]);
    }
    else {
      dt[x].add(in[to].back(), 1, 1);
      dt[x].add(in[to].back() + sz[to].back(), -1, y[to]);
    }
  }
  clearDFS(x, x);
  timer = 1;
  blocked[x] = true;
  for(int to : g[x]) {
      if(!blocked[to]) decompose(to);
  }
}

/*
ans += (dt[i].cnt[0] - to[0]) * to[4] + 
      (dt[i].cnt[2] - to[2]) * to[3] + 
      to[0] * (dt[i].cnt[4] - to[4]) + 
      to[2] * (dt[i].cnt[3] - to[3]);
        if(y[i] == 1) {
          ans += to[2] * (dt[i].cnt[0] - to[0]) + to[0] * (dt[i].cnt[2] - to[2]);
        }
        if(y[i] == 0) {
          ans += to[4];
        }
        if(y[i] == 2) {
          ans += to[3];
        } 
*/

void updCent0(int v, int id, ll sign) {
  ans += 2 * sign * (dt[v].cnt[4]); 
  dt[v].cnt[0] += sign;
}

void update0(int v, int id, ll sign) {
  int x = vec[v][id];
  
  int l = lead_in[v][id];
  vector <ll>&to = dt[x].cnts[l];
  if(v == x) {
    updCent0(v, id, sign);
    return;
  }
  int intm = in[v][id];
  int sztm = sz[v][id];
  ll cnt = dt[x].get(intm, 1);
  ans += 2 * sign * (dt[x].cnt[2] - to[2]) * cnt;
  ans += 2 * sign * (dt[x].cnt[4] - to[4]);
  if(y[x] == 1) {
    ans += 2 * sign * (dt[x].cnt[2] - to[2]);
  }
  to[0] += sign; dt[x].cnt[0] += sign;
  to[3] += sign * cnt;  dt[x].cnt[3] += cnt * sign;
  dt[x].s_bad += sign * to[2];
  dt[x].add(intm, sign, 0);
}

void updCent2(int v, int id, ll sign) {
  ans += 2 * sign * dt[v].cnt[3];
  dt[v].cnt[2] += sign;
}

void update2(int v, int id, ll sign) {
   int x = vec[v][id];
   
  if(v == x) {
    updCent2(v, id, sign);
    return;
  }
  int l = lead_in[v][id];
  vector <ll>&to = dt[x].cnts[l];
  int intm = in[v][id];
  int sztm = sz[v][id];
  ll cnt = dt[x].get(intm, 1);
  
  ans += 2 * sign * (dt[x].cnt[0] - to[0]) * cnt;
  ans += 2 * sign * (dt[x].cnt[3] - to[3]);
  
  if(y[x] == 1) {
    ans += 2 * sign * (dt[x].cnt[0] - to[0]);
  }
  to[2] += sign; dt[x].cnt[2] += sign;
  to[4] += sign * cnt;  dt[x].cnt[4] += sign * cnt;

  dt[x].s_bad += sign * to[0];
  
  dt[x].add(intm, sign, 2);
}

void updCent1(int v, ll sign) {
  ans += 2 * sign * (dt[v].cnt[0] * dt[v].cnt[2] - dt[v].s_bad);
  dt[v].cnt[1] += sign;
}

void update1(int v, int id, ll sign) {
   int x = vec[v][id];
  if(v == x) {
    updCent1(v, sign);
    return;
  }
  int l = lead_in[v][id];
  vector <ll>&to = dt[x].cnts[l];
  int intm = in[v][id];
  int sztm = sz[v][id];
 //cout << x << ' ' << intm << ' ' << sztm << ' ';
  ll num0 = dt[x].get(intm, intm + sztm - 1, 0);
 // cout << num0 << ' ' ;
  ll num2 = dt[x].get(intm, intm + sztm - 1, 2);
 // cout << num2 << '\n';
  ans += sign * 2 * num0 * (dt[x].cnt[2] - to[2]);
  ans += sign * 2 * num2 * (dt[x].cnt[0] - to[0]);
  to[1] += sign; to[3] += num0 * sign; to[4] += num2 * sign;
  dt[x].cnt[1] += sign; dt[x].cnt[3] += num0 * sign; dt[x].cnt[4] += num2 * sign;  
 
     dt[x].add(intm, sign, 1);
  dt[x].add(intm + sztm, -sign, 1);
  
}


void init(int n, std::vector<int> f, std::vector<int> u, std::vector<int> v,int q) {
    for(int i = 0; i < f.size(); i++) {
      y[i] = f[i];
    }
   // cout << 1;
    for(int i = 0; i < u.size(); i++) {
      g[u[i]].pb(v[i]);
      g[v[i]].pb(u[i]);
    }
   // cout << 1;
    decompose(0);
   // cout << 1;
    for(int i = 0; i < n; i++) {
     
      for(auto to : dt[i].cnts) {
        ans += (dt[i].cnt[0] - to[0]) * to[4] + (dt[i].cnt[2] - to[2]) * to[3] + to[0] * (dt[i].cnt[4] - to[4]) + to[2] * (dt[i].cnt[3] - to[3]);
        if(y[i] == 1) {
          ans += to[2] * (dt[i].cnt[0] - to[0]) + to[0] * (dt[i].cnt[2] - to[2]);
        }
        if(y[i] == 0) {
          ans += to[4];
        }
        if(y[i] == 2) {
          ans += to[3];
        } 
      }
     // cout << ans << ' ';
      
    }
}

void change(int X, int Y) {
  for(int i = 0; i < vec[X].size(); i++) {
    if(y[X] == 0) {
      update0(X, i, -1);
    }
    if(y[X] == 1)
    update1(X, i, -1);

    if(y[X] == 2) 
   update2(X, i, -1);
  }
 // return;
  y[X] = Y;
  for(int i = 0; i < vec[X].size(); i++) {
    if(y[X] == 0) {
      update0(X, i, 1);
    }
    
    if(y[X] == 1)
    update1(X, i, 1);
    if(y[X] == 2) 
    update2(X, i, 1);
  }
}

long long num_tours() {
  
  return ans / 2;
}
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...