2022/02/10 模拟赛题解
T1
Solution
比较水,就不说了。
T2
Solution
就是暴力优化,不知道复杂度为哈对,代码也过不了,就不放了。
T3
Solution
考虑暴力,即每次每个点向可以一波传染的点连边,然后缩点,求无入度的点数即可。
考虑优化,你发现对于两个点可以在点分树上一个点考虑先走到该点再到另一个点,所以我们可以直接淀粉质,然后双指针拆点连边即可。
Code
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define ll long long
#define MAXM 6000005
#define MAXN 300005
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}
int n,m,r[MAXN];
struct edge{
int v,w;
};
vector <int> E[MAXM];
vector <edge> g[MAXN];
stack <int> S;
bool vis[MAXM];
int ind,tot,dfn[MAXM],low[MAXM],bel[MAXM];
void tarjan (int u){
S.push (u),vis[u] = 1,dfn[u] = low[u] = ++ ind;
for (Int v : E[u])
if (!dfn[v]) tarjan (v),chkmin (low[u],low[v]);
else if (vis[v]) chkmin (low[u],dfn[v]);
if (dfn[u] == low[u]){
++ tot;
while (1){
int now = S.top();S.pop ();
bel[now] = tot,vis[now] = 0;
if (now == u) break;
}
}
}
ll dep[MAXN];
int all,root,siz[MAXN],mxs[MAXN];
void findroot (int u,int fa){
siz[u] = 1,mxs[u] = 0;
for (edge it : g[u]){
int v = it.v,w = it.w;
if (v == fa || vis[v]) continue;
findroot (v,u),chkmax (mxs[u],siz[v]),siz[u] += siz[v];
}
chkmax (mxs[u],all - siz[u]);
if (!root || mxs[u] < mxs[root]) root = u;
}
int cnt,tS[MAXN],pS[MAXN];
void dfs (int u,int fa,ll dpt){
pS[cnt] = u,tS[cnt] = u,cnt ++,dep[u] = dpt;
for (edge it : g[u]){
int v = it.v,w = it.w;
if (v == fa || vis[v]) continue;
dfs (v,u,dpt + w);
}
}
void link (int u,int v){
E[u].push_back (v);
}
void workit (int u){
vis[u] = 1,cnt = 0,dfs (u,0,0);
sort (tS,tS + cnt,[](int x,int y){return dep[x] < dep[y];});
sort (pS,pS + cnt,[](int x,int y){return r[x] - dep[x] < r[y] - dep[y];});
for (Int i = 0,t = 0;i < cnt;++ i){
int x = pS[i];
if (r[x] - dep[x] < 0) continue;
++ m;if (t) link (m,m - 1);link (x,m);
while (t < cnt && dep[tS[t]] <= r[x] - dep[x]) link (m,tS[t]),++ t;
}
for (edge it : g[u]){
int v = it.v;
if (vis[v]) continue;
all = siz[v],root = 0,findroot (v,0),workit (root);
}
}
signed main(){
freopen ("infect.in","r",stdin);
freopen ("infect.out","w",stdout);
read (n);
for (Int i = 1;i <= n;++ i) read (r[i]);
for (Int i = 2,u,v,w;i <= n;++ i) read (u,v,w),g[u].push_back ({v,w}),g[v].push_back ({u,w});
m = all = n,findroot (1,0),workit (root),memset (vis,0,sizeof (vis));
for (Int i = 1;i <= m;++ i) if (!dfn[i]) tarjan (i);
for (Int u = 1;u <= m;++ u) for (Int v : E[u]) if (bel[u] != bel[v]) vis[bel[v]] = 1;
int ans = 0;
for (Int i = 1;i <= tot;++ i) ans += (!vis[i]);
write (ans),putchar ('\n');
return 0;
}