|
|
package old; |
|
|
|
|
|
import java.util.*; |
|
|
import java.util.function.Consumer; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class clique2_ablations_compat { |
|
|
|
|
|
public static List<SnapshotDTO> runLaplacianRMC(List<Integer>[] adj1Based) { |
|
|
ArrayList<SnapshotDTO> out = new ArrayList<>(); |
|
|
runLaplacianRMCStreaming(adj1Based, out::add); |
|
|
return out; |
|
|
} |
|
|
|
|
|
public static void runLaplacianRMCStreaming(List<Integer>[] adj1Based, |
|
|
Consumer<SnapshotDTO> sink) { |
|
|
final int n = adj1Based.length - 1; |
|
|
int[][] nbrs = new int[n][]; |
|
|
int[] degFull = new int[n]; |
|
|
for (int u1 = 1; u1 <= n; u1++) { |
|
|
List<Integer> lst = adj1Based[u1]; |
|
|
int m = lst.size(); |
|
|
int[] arr = new int[m]; |
|
|
for (int i = 0; i < m; i++) arr[i] = lst.get(i) - 1; |
|
|
nbrs[u1 - 1] = arr; |
|
|
degFull[u1 - 1] = m; |
|
|
} |
|
|
|
|
|
|
|
|
int[] order = (n <= 100_000) ? degeneracyOrderStable(nbrs, degFull) |
|
|
: degeneracyOrderBucket(nbrs, degFull); |
|
|
|
|
|
DSU dsu = new DSU(n); |
|
|
boolean[] added = new boolean[n]; |
|
|
int[] degC = new int[n]; |
|
|
|
|
|
double[] S3 = new double[n]; |
|
|
double[] P = new double[n]; |
|
|
|
|
|
for (int step = n - 1; step >= 0; step--) { |
|
|
final int u = order[step]; |
|
|
added[u] = true; |
|
|
dsu.makeSingleton(u); |
|
|
|
|
|
|
|
|
int[] Nu = nbrs[u]; |
|
|
int t = 0; |
|
|
for (int v : Nu) if (added[v]) t++; |
|
|
|
|
|
|
|
|
int[] neigh = new int[t]; |
|
|
int k = 0; |
|
|
long sum_b = 0L; |
|
|
long sum_b2 = 0L; |
|
|
for (int v : Nu) { |
|
|
if (!added[v]) continue; |
|
|
neigh[k++] = v; |
|
|
int b = degC[v]; |
|
|
sum_b += b; |
|
|
sum_b2 += (long) b * (long) b; |
|
|
} |
|
|
|
|
|
|
|
|
int ru = dsu.find(u); |
|
|
for (int i = 0; i < t; i++) { |
|
|
int rv = dsu.find(neigh[i]); |
|
|
if (ru != rv) ru = dsu.union(ru, rv); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
double deltaS3 = (double) t * t * t + 3.0 * (double) sum_b2 + 3.0 * (double) sum_b + (double) t; |
|
|
|
|
|
|
|
|
|
|
|
double deltaP = 0.0; |
|
|
for (int i = 0; i < t; i++) { |
|
|
int v = neigh[i]; |
|
|
int b = degC[v]; |
|
|
|
|
|
int rv = dsu.find(v); |
|
|
long sNv = 0L; |
|
|
for (int w : nbrs[v]) { |
|
|
if (!added[w]) continue; |
|
|
if (dsu.find(w) != rv) continue; |
|
|
sNv += degC[w]; |
|
|
} |
|
|
deltaP += (double) t * (double) (b + 1) + (double) sNv; |
|
|
} |
|
|
|
|
|
|
|
|
S3[ru] += deltaS3; |
|
|
P[ru] += deltaP; |
|
|
|
|
|
|
|
|
int[] nodes = dsu.nodesOf(ru); |
|
|
long sumDegIn2 = dsu.sumDegIn2(ru); |
|
|
double Q = 2.0 * (S3[ru] - P[ru]); |
|
|
sink.accept(new SnapshotDTO(nodes, nodes.length, sumDegIn2, Q)); |
|
|
|
|
|
|
|
|
degC[u] += t; |
|
|
for (int i = 0; i < t; i++) { |
|
|
int v = neigh[i]; |
|
|
degC[v] += 1; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int[] degeneracyOrderStable(int[][] nbrs, int[] deg0) { |
|
|
final int n = nbrs.length; |
|
|
int[] deg = Arrays.copyOf(deg0, n); |
|
|
boolean[] removed = new boolean[n]; |
|
|
PriorityQueue<long[]> pq = new PriorityQueue<>(Comparator.comparingLong(a -> (a[0] << 21) | a[1])); |
|
|
for (int u = 0; u < n; u++) pq.add(new long[]{deg[u], u}); |
|
|
int[] order = new int[n]; |
|
|
int ptr = 0; |
|
|
while (ptr < n) { |
|
|
long[] top = pq.poll(); |
|
|
int du = (int) top[0]; |
|
|
int u = (int) top[1]; |
|
|
if (removed[u] || du != deg[u]) continue; |
|
|
removed[u] = true; |
|
|
order[ptr++] = u; |
|
|
for (int v : nbrs[u]) if (!removed[v]) { |
|
|
deg[v]--; |
|
|
pq.add(new long[]{deg[v], v}); |
|
|
} |
|
|
} |
|
|
return order; |
|
|
} |
|
|
|
|
|
static int[] degeneracyOrderBucket(int[][] nbrs, int[] deg0) { |
|
|
final int n = nbrs.length; |
|
|
int maxDeg = 0; |
|
|
for (int d : deg0) if (d > maxDeg) maxDeg = d; |
|
|
|
|
|
int[] deg = Arrays.copyOf(deg0, n); |
|
|
int[] head = new int[Math.max(2, maxDeg + 2)]; |
|
|
int[] next = new int[n]; |
|
|
int[] prev = new int[n]; |
|
|
Arrays.fill(head, -1); |
|
|
Arrays.fill(next, -1); |
|
|
Arrays.fill(prev, -1); |
|
|
for (int u = 0; u < n; u++) { |
|
|
int d = deg[u]; |
|
|
next[u] = head[d]; |
|
|
if (head[d] >= 0) prev[head[d]] = u; |
|
|
head[d] = u; |
|
|
} |
|
|
|
|
|
boolean[] removed = new boolean[n]; |
|
|
int[] order = new int[n]; |
|
|
int ptr = 0; |
|
|
int cur = 0; |
|
|
while (cur <= maxDeg && head[cur] < 0) cur++; |
|
|
|
|
|
for (int it = 0; it < n; it++) { |
|
|
while (cur <= maxDeg && head[cur] < 0) cur++; |
|
|
if (cur > maxDeg) cur = maxDeg; |
|
|
int u = head[cur]; |
|
|
head[cur] = next[u]; |
|
|
if (head[cur] >= 0) prev[head[cur]] = -1; |
|
|
next[u] = prev[u] = -1; |
|
|
removed[u] = true; |
|
|
order[ptr++] = u; |
|
|
|
|
|
for (int v : nbrs[u]) if (!removed[v]) { |
|
|
int dv = deg[v]; |
|
|
int pv = prev[v], nv = next[v]; |
|
|
if (pv >= 0) next[pv] = nv; else head[dv] = nv; |
|
|
if (nv >= 0) prev[nv] = pv; |
|
|
int nd = dv - 1; |
|
|
deg[v] = nd; |
|
|
next[v] = head[nd]; |
|
|
if (head[nd] >= 0) prev[head[nd]] = v; |
|
|
prev[v] = -1; |
|
|
head[nd] = v; |
|
|
if (nd < cur) cur = nd; |
|
|
} |
|
|
} |
|
|
return order; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static final class DSU { |
|
|
final int n; |
|
|
final int[] parent; |
|
|
final int[] size; |
|
|
final long[] sumDegIn2; |
|
|
final IntList[] members; |
|
|
|
|
|
DSU(int n) { |
|
|
this.n = n; |
|
|
this.parent = new int[n]; |
|
|
this.size = new int[n]; |
|
|
this.sumDegIn2 = new long[n]; |
|
|
this.members = new IntList[n]; |
|
|
for (int i = 0; i < n; i++) { |
|
|
parent[i] = i; |
|
|
size[i] = 0; |
|
|
sumDegIn2[i] = 0L; |
|
|
members[i] = new IntList(); |
|
|
} |
|
|
} |
|
|
|
|
|
void makeSingleton(int u) { |
|
|
parent[u] = u; |
|
|
size[u] = 1; |
|
|
sumDegIn2[u] = 0L; |
|
|
members[u].clear(); |
|
|
members[u].add(u); |
|
|
} |
|
|
|
|
|
int find(int x) { |
|
|
int r = x; |
|
|
while (r != parent[r]) r = parent[r]; |
|
|
int y = x; |
|
|
while (y != r) { int p = parent[y]; parent[y] = r; y = p; } |
|
|
return r; |
|
|
} |
|
|
|
|
|
int union(int ra, int rb) { |
|
|
ra = find(ra); rb = find(rb); |
|
|
if (ra == rb) return ra; |
|
|
if (size[ra] < size[rb]) { int t = ra; ra = rb; rb = t; } |
|
|
parent[rb] = ra; |
|
|
size[ra] += size[rb]; |
|
|
sumDegIn2[ra] += sumDegIn2[rb]; |
|
|
members[ra].addAll(members[rb]); |
|
|
members[rb].clear(); |
|
|
return ra; |
|
|
} |
|
|
|
|
|
long sumDegIn2(int r) { return sumDegIn2[find(r)]; } |
|
|
|
|
|
int[] nodesOf(int r) { |
|
|
return members[find(r)].toArray(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static final class IntList { |
|
|
int[] a; int sz; |
|
|
IntList() { a = new int[4]; sz = 0; } |
|
|
void clear() { sz = 0; } |
|
|
void add(int x) { if (sz == a.length) a = Arrays.copyOf(a, sz << 1); a[sz++] = x; } |
|
|
void addAll(IntList other) { |
|
|
if (other.sz == 0) return; |
|
|
int need = sz + other.sz; |
|
|
if (need > a.length) { |
|
|
int cap = a.length; |
|
|
while (cap < need) cap <<= 1; |
|
|
a = Arrays.copyOf(a, cap); |
|
|
} |
|
|
System.arraycopy(other.a, 0, a, sz, other.sz); |
|
|
sz = need; |
|
|
} |
|
|
int[] toArray() { return Arrays.copyOf(a, sz); } |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static final class SnapshotDTO { |
|
|
public final int[] nodes; |
|
|
public final int nC; |
|
|
public final long sumDegIn; |
|
|
public final double Q; |
|
|
|
|
|
public SnapshotDTO(int[] nodes, int nC, long sumDegIn, double Q) { |
|
|
this.nodes = nodes; |
|
|
this.nC = nC; |
|
|
this.sumDegIn = sumDegIn; |
|
|
this.Q = Q; |
|
|
} |
|
|
} |
|
|
} |
|
|
|