题解:P14269 [ROI 2015 Day2] 警报系统
LastKismet · · 题解
Sol
一个暴力做法是,对于每个点,将其向其可以触发的点连有向边,最后答案就是入度为零的 SCC 数。
考虑优化建图,发现每次连边都是给一个距离前缀连边的形式,因此想到前缀和优化建图,然而图上并不方便直接找到与每个点距离前缀的链。
考虑点分治,每个分治块中所有点按分支中心距离升序排序得到一条虚链,然后对分治块中每个点都二分找到这条虚链上可连接的前缀连边。这样连出来的边数是
值得注意的是,最后算答案时,一些没有被经过过的虚点应当删去,从所有实点搜一遍即可找出要被删除的节点。
最后,时空限制对于我这种大常熟选手来说还是有点紧了。qwq
Code
由于卡常略显丑陋。
const int N=3e5+5,NN=6e6+5;
int n,nn;
ll r[N];
vec<pil> g[N];
vec<int> G[NN];
bool don[N];
int siz,sz[N];
void gsiz(int x,int fa){
sz[x]=1;
for(auto e:g[x]){
int y=e.fir;
if(y==fa||don[y])continue;
gsiz(y,x);
sz[x]+=sz[y];
}
}
int rot,mx[N];
void grot(int x,int fa){
mx[x]=siz-sz[x];
for(auto e:g[x]){
int y=e.fir;
if(y==fa||don[y])continue;
grot(y,x);
chmax(mx[x],sz[y]);
}
if(mx[x]<mx[rot])rot=x;
}
int fa[N];
vec<int> son;
vec<ll> dep;ll dis[N];
int to[N];
void dfs(int x,int fa){
son.pub(x);dep.pub(dis[x]);++n,G[n].pub(x),to[x]=n;
for(auto e:g[x]){
int y=e.fir;
if(y==fa||don[y])continue;
dis[y]=dis[x]+e.sec;
dfs(y,x);
}
}
void dfs1(int x,int fa){
ll d=r[x]-dis[x];
int k=upper_bound(dep.begin(),dep.end(),d)-dep.begin()-1;
if(k>=0)G[x].pub(to[son[k]]);
for(auto e:g[x]){
int y=e.fir;
if(y==fa||don[y])continue;
dfs1(y,x);
}
}
void calc(int x,int Fa){
gsiz(x,0),siz=sz[x];
mx[rot=0]=inf,grot(x,0);
x=rot,fa[x]=Fa;
son.clear(),dep.clear();
dis[x]=0;dfs(x,0);
sort(son.begin(),son.end(),[&](int a,int b){return dis[a]<dis[b];});
sort(dep.begin(),dep.end());
int z=x;ll d;int c=1;
per(i,son.size()-1,1)G[to[son[i]]].pub(to[son[i-1]]);
dfs1(x,0);
don[x]=1;
for(auto e:g[x]){
int y=e.fir;
if(don[y])continue;
calc(y,x);
}
}
int scnt,dcnt,top;
vec<int> dg,scc,dfn,low,stk;vec<bool> ins,pd,pd2;
void tarjan(int x){
dfn[x]=low[x]=++dcnt;
stk[++top]=x,ins[x]=1;
for(auto y:G[x]){
if(!dfn[y])tarjan(y),chmin(low[x],low[y]);
else if(ins[y])chmin(low[x],dfn[y]);
}
if(low[x]>=dfn[x]){
++scnt;
while(1){
int tp=stk[top--];ins[tp]=0;
scc[tp]=scnt;
if(tp==x)break;
}
}
}
void dfs(int x){
pd[x]=1;pd2[scc[x]]=pd2[scc[x]]|pd[x];
for(auto y:G[x])if(!pd[y])dfs(y);
}
inline void Main(){
cin>>n;nn=n;
rep(i,1,n)cin>>r[i];
rep(i,2,n){
int a,b,c;cin>>a>>b>>c;
g[a].pub({b,c}),g[b].pub({a,c});
}
calc(1,0);
scc.resize(n+1),dfn.resize(n+1),low.resize(n+1),stk.resize(n+1),ins.resize(n+1),pd.resize(n+1);
rep(i,1,n)if(!dfn[i])tarjan(i);
dg.resize(scnt+1),pd2.resize(scnt+1);
rep(i,1,nn)dfs(i);
rep(i,1,n)for(auto j:G[i])if(scc[i]!=scc[j]&&pd[i])++dg[scc[j]];
int ans=0;
rep(i,1,scnt)if(!dg[i])ans+=pd2[i];
put(ans);
}