Cod sursă (job #816416)

Utilizator avatar Catalin.Francu Cătălin Frâncu Catalin.Francu IP ascuns
Problemă Risipă Compilator cpp-32 | 2,94 kb
Rundă Arhiva de probleme Status evaluat
Dată 27 mar. 2025 12:58:11 Scor 100
// Metodă: Construim graful transpus, pe care punem întrebarea: care este
// profitul din fiecare nod u pînă în nodul h? Calculăm componentele tare
// conexe cu algoritmul lui Tarjan. Fiecare componentă calculează două valori:
//
// 1. Pe parcursul explorării acelei CTC, profitul maxim pe o muchie externă
// spre o altă CTC care are, la rîndul ei, drum spre h.
//
// 2. La finalul explorării, odată ce cunoaștem nodurile din CTC, suma
// costurilor acelor noduri.
//
// La finalul explorării, propagăm suma celor două valori la fiecare nod din
// CTC, ca să le putem răspunde altor noduri viitoare care au muchii înspre
// această CTC.
//
// v2: liste proprii
#include <stdio.h>

const int MAX_NODES = 100'000;
const int MAX_EDGES = 300'000;

struct cell {
  int v, next;
};

struct node {
  int adj;
  int subtree_cost; // costul din magazinele din subarborele DFS
  int total;    // costul maxim pînă în h sau 0 dacă nu putem ajunge în h

  int time;
  int low;
  bool on_stack;
  bool can_reach_h;
};

node nd[MAX_NODES + 1];
cell list[MAX_EDGES + 1];
int st[MAX_NODES], ss; // stiva DFS
int n, hotel;

void read_data() {
  FILE* f = fopen("risipa.in", "r");
  int m, u, v, ptr = 1;
  fscanf(f, "%d %d %d", &n, &m, &hotel);
  for (u = 1; u <= n; u++) {
    fscanf(f, "%d", &nd[u].subtree_cost);
  }

  while (m--) {
    fscanf(f, "%d %d", &u, &v);
    list[ptr] = { u, nd[v].adj }; // construim graful transpus
    nd[v].adj = ptr++;
  }
  fclose(f);
}

void minimize(int& x, int y) {
  if (y < x) {
    x = y;
  }
}

void maximize(int& x, int y) {
  if (y > x) {
    x = y;
  }
}

void pull_cost(int u, int v) {
  maximize(nd[u].total, nd[v].total);
  if (nd[v].on_stack) {
    nd[u].subtree_cost += nd[v].subtree_cost;
    nd[v].subtree_cost = 0; // evită dubla contabilitate
  }
}

void pop_scc(int root) {
  int total = nd[root].can_reach_h
    ? (nd[root].subtree_cost + nd[root].total)
    : 0;

  int v;
  do {
    v = st[--ss];
    nd[v].on_stack = false;
    nd[v].total = total;
    nd[v].can_reach_h = nd[root].can_reach_h;
  } while (v != root);
}

void dfs(int u) {
  static int time = 0;
  nd[u].time = nd[u].low = ++time;
  nd[u].on_stack = true;
  st[ss++] = u;

  nd[u].can_reach_h = (u == hotel);

  for (int ptr = nd[u].adj; ptr; ptr = list[ptr].next) {
    int v = list[ptr].v;
    if (!nd[v].time) {
      dfs(v);
      nd[u].can_reach_h |= nd[v].can_reach_h;
      minimize(nd[u].low, nd[v].low);
    } else if (nd[v].on_stack) {
      minimize(nd[u].low, nd[v].time);
    } else {
      nd[u].can_reach_h |= nd[v].can_reach_h;
    }

    pull_cost(u, v);
  }

  if (nd[u].low == nd[u].time) {
    pop_scc(u);
  }
}

void dfs_wrapper() {
  for (int u = 1; u <= n; u++) {
    if (!nd[u].time) {
      dfs(u);
    }
  }
}

void write_answers() {
  FILE* f = fopen("risipa.out", "w");
  for (int u = 1; u <= n; u++) {
    fprintf(f, "%d\n", nd[u].total);
  }
  fclose(f);
}

int main() {
  read_data();
  dfs_wrapper();
  write_answers();

  return 0;
}