[Simulation Competition] infection (point division, strong connected component reduction point)

Posted by Janjan on Thu, 10 Feb 2022 21:07:32 +0100

background

One day, a group of dogs suddenly began to moisten people in the past, so the students banned this part of the science and technology building.
  ~  
Deadcodes: old machine room

Problem surface

Your country n n n cities, yes n − 1 n-1 n − 1 road connection, and all cities are accessible to each other. Cities have an infectious power because of their own traffic and population factors r i r_i ri, once the epidemic breaks out in this city, it will spread rapidly to less than or equal to the distance from it r i r_i Other cities in China, and caused a chain reaction. Q: at least a few outbreaks in the beginning will lead to the whole country n n All n cities were infected.

512   M B     3   s \tt512\,MB~~~3\,s 512MB   3s

input

One in the first line n n n. Second line n n n number r i r_i ri​ .

next n − 1 n-1 n − 1 line, three numbers per line a i , b i , d i a_i,b_i,d_i ai, bi, di, denotes a i a_i ai Chenghe b i b_i There is a road between the two cities with a length of d i d_i A two-way road.

1 ≤ n ≤ 3 × 1 0 5   ,   0 ≤ r i , d i ≤ 1 0 9 1\leq n\leq3\times10^5~,~0\leq r_i,d_i\leq10^9 1≤n≤3×105 , 0≤ri​,di​≤109.

output

A number indicates the outbreak of epidemic disease in at least several cities at the beginning.

Problem solution

A city a a a outbreak of epidemic disease will affect cities b b b. Can be abstracted as a a a a to b b The directed edge of b.

If we get this directed graph, then we reduce its strongly connected components to obtain D A G \tt DAG DAG, the answer is D A G \tt DAG The number of points with DAG penetration of 0!

That's the obvious O ( n 2 ) O(n^2) The unreliable idea of O(n2) can lead to a positive solution.

Due to too many edges, we can't get this directed graph. Can we think about optimizing the construction of the graph?

A directed edge a → b a\rightarrow b A → b, which essentially corresponds to a length not exceeding r a r_a Path on tree a → b a\rightarrow b a → b, so we can use the magic algorithm of statistical path - point divide and conquer to explore how to optimize the drawing.

When we stand on the center of gravity of a subgraph and consider the contribution of the connected block, we will take the center of gravity as the root and traverse the whole subtree to get the distance from each point to the root. At this time, the points are sorted from small to large according to the distance to the root, which is the sequence a r ar ar, considering the other points that each point can affect, it must be a r ar A prefix of ar! So we can use lower_bound finds the end of the prefix and builds a map with prefix and optimization. On the way to establish O ( n log ⁡ n ) O(n\log n) O(nlogn) virtual points, and finally delete the virtual points that no real point can reach.

Spatial complexity O ( n log ⁡ n ) O(n\log n) O(nlogn), time complexity O ( n log ⁡ 2 n ) O(n\log^2n) O(nlog2n), considering the time complexity, the bottlenecks are sorting and lower_bound, which can be achieved by cardinality sorting, TwoPointer and other optimizations O ( n log ⁡ n ) O(n\log n) O(nlogn) .

CODE

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<random>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 300005
#define LL long long
#define ULL unsigned long long
#define ENDL putchar('\n')
#define DB long double
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
int xchar() {
	static const int maxn = 1000000;
	static char b[maxn];
	static int pos = 0,len = 0;
	if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
	if(pos == len) return -1;
	return b[pos ++];
}
//#define getchar() xchar()
LL read() {
	LL f = 1,x = 0;int s = getchar();
	while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
	while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
	return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
void putnum(LL x) {
	if(!x) {putchar('0');return ;}
	if(x<0) putchar('-'),x = -x;
	return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);}

int n,m,s,o,k;
int hd[MAXN],nx[MAXN<<1],v[MAXN<<1],w[MAXN<<1],cne;
void ins(int x,int y,int z) {
	nx[++cne] = hd[x]; v[cne] = y; w[cne] = z; hd[x] = cne;
}
int r[MAXN];
vector<int> g[MAXN*20];
int ind[MAXN];
void ins2(int x,int y) {if(x&&y) g[x].push_back(y);}
bool FLAG,f[MAXN];
int d[MAXN],siz[MAXN],fe[MAXN],SIZ,hv;
int ar[MAXN],cna,b[MAXN],c[MAXN];
bool cmp(int a,int b) {return d[a] < d[b];}
void dfs(int x,int ff) {
	if(FLAG) {
		if(ff)d[x] = d[ff] + fe[x];
		else d[x] = 0;
		d[x] = min(d[x],1000000005);
		if(d[x] <= 1000000000) ar[++ cna] = x;
	}
	siz[x] = 1;
	bool fl = 1;
	for(int i = hd[x];i;i = nx[i]) {
		if(v[i] != ff && !f[v[i]]) {
			fe[v[i]] = w[i];
			dfs(v[i],x);
			siz[x] += siz[v[i]];
			if(siz[v[i]] > (SIZ>>1)) fl = 0;
		}
	}
	if(fl && SIZ-siz[x] <= (SIZ>>1)) hv = x;
	return ;
}
void calc(int x) {
	FLAG = 1;d[x] = 0;cna = 0;
	dfs(x,0);
	sort(ar + 1,ar + cna + 1,cmp);
	b[0] = 0;
	for(int i = 1;i <= cna;i ++) {
		b[i] = ++ m; c[i] = d[ar[i]];
		ins2(b[i],b[i-1]); ins2(b[i],ar[i]);
	}
	int fr = 0;
	for(int i = 1;i <= cna;i ++) {
		int ds = r[ar[i]] - d[ar[i]];
		if(ds < 0) continue;
		int ad = upper_bound(c + 1,c + cna + 1,ds) - c - 1;
		while(ad < cna && c[ad+1] <= ds) ad ++;
		if(c[ad] > ds) ad --;
		ins2(ar[i],b[ad]); fr = max(fr,ad);
	}
	while(fr > 0) ind[ar[fr]] ++,fr --;
	FLAG = 0;
	return ;
}
void solve(int x) {
	calc(x);
	f[x] = 1;
	for(int i = hd[x];i;i = nx[i]) {
		if(!f[v[i]]) {
			SIZ = siz[v[i]];
			dfs(v[i],0);
			solve(hv);
		}
	}return ;
}
int fn[MAXN];
bool vs[MAXN*20],ha[MAXN*20];
int dfn[MAXN*20],low[MAXN*20],tim;
int st[MAXN*20],tp,cnb;
void dfs0(int x) {
	dfn[x] = low[x] = ++ tim;
	st[++ tp] = x; vs[x] = 1;
	for(int i = 0,le = g[x].size();i < le;i ++) {
		int y = g[x][i];
		if(!dfn[y]) {
			dfs0(y);
			low[x] = min(low[x],low[y]);
			if(!vs[y]) ha[dfn[y]] = 0;
		}
		else if(vs[y]) {
			low[x] = min(low[x],dfn[y]);
		}
		else ha[dfn[y]] = 0;
	}
	if(dfn[x] == low[x]) {
		cnb ++;
		while(vs[x]) {
			dfn[st[tp]] = cnb;
			if(st[tp] <= n) ha[cnb] = 1;
			vs[st[tp --]] = 0;
		}
	}return ;
}
int main() {
	freopen("infect.in","r",stdin);
	freopen("infect.out","w",stdout);
	n = read();m = n;
	for(int i = 1;i <= n;i ++) {
		r[i] = read();
	}
	for(int i = 1;i < n;i ++) {
		s = read(); o = read(); k = read();
		ins(s,o,k); ins(o,s,k);
	}
	SIZ = n;
	dfs(1,0);
	solve(hv);
	for(int i = 1;i <= n;i ++) fn[i] = i;
	sort(fn + 1,fn + 1 + n,[](int a,int b){
		return r[a] > r[b];
	});
	int ans = 0;
	for(int i = 1;i <= n;i ++) {
		if(!dfn[fn[i]]) {
			dfs0(fn[i]);
		}
	}
	for(int i = 1;i <= cnb;i ++) ans += ha[i];
	AIput(ans,'\n');
	return 0;
}

Topics: Algorithm Graph Theory tree partitioning