제출 #409482

#제출 시각아이디문제언어결과실행 시간메모리
409482pauloamedRailway (BOI17_railway)C++14
100 / 100
693 ms121788 KiB
#include<bits/stdc++.h>
using namespace std;

#define MAXN 500010
#define MAXLOG 21

// global time var for computing the following arrays
// (only incremented when entering node)
int currTime;
// inTime[v]: time in which node v was entered
// outTime[v]: time in which node v was left
// time2node[t]: node which was entered in time t
// inTime[time2Node[t]] = t // time2Node[inTime[v]] = v
int inTime[MAXN], outTime[MAXN], time2Node[MAXN];
int sz[MAXN]; // sz[v]: size of subtree rooted at v
vector<int> v[MAXN]; // adj list
int depth[MAXN];

// pra cada conjunto de nos eu guardo que ali comeca a query q
vector<int> queriesStart[MAXN];

// pra cada LCA de um conjunto de nos eu guardo que ali acaba a query i
vector<int> queriesEnd[MAXN];

void precalc(int x, int par, int d){
  time2Node[currTime] = x; inTime[x] = currTime++;
  depth[x] = d;
  sz[x] = queriesStart[x].size() + queriesEnd[x].size() + 1;
  for(auto y : v[x]){
    if(y == par) continue;
    precalc(y, x, d + 1);
    sz[x] += sz[y];
  }
  outTime[x] = currTime;
}

bool isInSubtreeOf(int x, int y){
  return inTime[x] >= inTime[y] && outTime[x] <= outTime[y];
}



int ans[MAXN];
int timeAns[MAXN];

map<int,int> on;
set<int> off;

map<pair<int,int>, int> edge2id;

void solve(int x, int par, bool keep){
  // retrieving heavy child from x
  int heavyChildSize = -1;
  int heavyChild = -1;
  for(auto y : v[x]){
    if(y == par) continue;
    if(sz[y] > heavyChildSize){
      heavyChild = y;
      heavyChildSize = sz[y];
    }
  }

  // vising light and then heavy childs of x
  for(auto y : v[x]){
    if(y == heavyChild || y == par) continue;
    solve(y, x, false);
  }
  if(heavyChild != -1) solve(heavyChild, x, true);

  for(auto y : v[x]){
    if(y == heavyChild || y == par) continue;
    for(int t = inTime[y]; t < outTime[y]; ++t){
      int z = time2Node[t];
      for(auto y : queriesStart[z]) on[y]++;
      for(auto y : queriesEnd[z]) off.insert(y);
    }
  }

  for(auto y : queriesStart[x]) on[y]++;
  for(auto y : queriesEnd[x]) off.insert(y);

  // cout << "========================\n";
  // cout << x << "\n";
  // for(auto y : on) cout << y.first << " " << y.second << ", "; cout << "\n";
  // for(auto y : off) cout << y << " "; cout << "\n";
  // cout << "========================\n";

  ans[edge2id[{x, par}]] = on.size() - off.size();

  if(!keep){
    for(int t = inTime[x]; t < outTime[x]; ++t){
      int z = time2Node[t];
      for(auto y : queriesEnd[z]){
        off.erase(y);
      }
      for(auto y : queriesStart[z]){
        on[y]--;
        if(on[y] == 0) on.erase(y);
      }
    }
  }
}


int st[MAXN][MAXLOG]; // sparse table (x,i) guardando ancestral de ordem 2^i de x
bool vis_lca[MAXN]; // lvl=profundidade de cada no

void init_dfs(int x, int par){
    vis_lca[x] = true; // marcando vertice como visitado
    st[x][0] = par; // o ancestral de ordem 2^0 (1) de x eh o pai dele
    // se tiver pai valido (!= raiz), a prof aumenta em 1
    if(par != -1) depth[x] = depth[par] + 1;

    for(int i = 0; i < v[x].size(); ++i) // visitar todos adjacentes
        if(!vis_lca[v[x][i]]) init_dfs(v[x][i], x); // passo recursivo
}

void init_st(){
    // processo cada nivel de cada vertice
    for(int x = 1; x < MAXLOG; ++x) // 2^0 ja foi calculado, calculo pro resto
        for(int i = 0; i < MAXN; ++i){ // pra cada vertice
            // olho o ancestral 2^(i-1) do meu 2^(i-1), achando entao o meu 2^i
            if(st[i][x-1] == -1) st[i][x] = -1;
            else st[i][x] = st[st[i][x-1]][x-1];
    }
}

void init(int root, int n){ // funcao init, raiz e #nos
    // botando que o pai da raiz eh -1, pode ser ela mesma tbm
    init_dfs(root, -1); // calcular os ancestrais imediatos
    init_st(); // init da sparse table
}


int lca(int x, int y){ // lca de x e y
    // cout << lvl[x] << " " << lvl[y] << endl;
    if(depth[x] < depth[y]) swap(x, y); // quero q x seja mais profundo q y

    int falta_subir = (depth[x] - depth[y]); // igualo as profundidades
    // simples representacao binaria de (falta_subir)
    for(int i = MAXLOG-1; i >= 0; --i){ // encontro os bits para representar o
        if((1<<i) <= falta_subir){ //      numero, dos mais signif. para os menos
            falta_subir -= (1<<i);
            x = st[x][i];
        }
    }

    if(x == y) return x; // ocorre quando x ta numa subarvore de y

    // acho o ponto abaixo do encontro (LCA)
    // se eu tentar subir 2^i e eles ja estiverem juntos, nao subo
    // tento entao subir 2^(i-1)
    for(int i = MAXLOG-1; i >= 0; --i){
        if(st[x][i] != st[y][i]){ // se continuarem diferentes, subo
            x = st[x][i]; // subindo pra x
            y = st[y][i]; // subindo pra y
        }
    }

    return st[x][0]; // retornando o ponto de encontro
}

int main(){
  ios::sync_with_stdio(false);
  int n, m, k; cin >> n >> m >> k;

  for(int i = 1; i < n; ++i){
    int a, b; cin >> a >> b; a--, b--;
    v[a].push_back(b);
    v[b].push_back(a);
    edge2id[{a, b}] = i;
    edge2id[{b, a}] = i;
  }

  init(0, n);

  for(int i = 0; i < m; ++i){
    int s; cin >> s;
    vector<int> nodes(s);
    for(auto &x : nodes){
      cin >> x; x--;
    }
    int lcax = nodes[0];
    for(int i = 1; i < s; ++i){
      lcax = lca(lcax, nodes[i]);
    }
    // cerr << i << " " << lcax << endl;
    for(auto x : nodes){
      if(x == lcax) continue;
      queriesStart[x].push_back(i);
    }
    queriesEnd[lcax].push_back(i);
  }


  precalc(0, -1, 0);
  solve(0, -1, true);

  vector<int> anss;
  for(int i = 1; i <= n; ++i){
    // cout << i << " " << ans[i] << endl;
    if(ans[i] >= k) anss.push_back(i);
  }

  cout << anss.size() << "\n";
  for(auto x : anss) cout << x << " ";
  cout << "\n";
}

컴파일 시 표준 에러 (stderr) 메시지

railway.cpp: In function 'void init_dfs(int, int)':
railway.cpp:114:22: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  114 |     for(int i = 0; i < v[x].size(); ++i) // visitar todos adjacentes
      |                    ~~^~~~~~~~~~~~~
#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...