题解 CF757F 【Team Rocket Rises Again】

AThousandSuns

2021-03-21 09:32:13

Solution

《关于我随机开 CF 然后刷到支配树模板自闭一万年这件事》 那么,如果像我一样,不会支配树~~也不想学~~怎么办呢? --- 提供一个时间复杂度 $O(n+m\log n)$(瓶颈在最短路),空间复杂度 $O(n+m)$,不需要支配树(我相信我没有自己发明),更不需要倍增 LCA 和 LCT 的做法。 (截至 2021.3.21,该做法在 CF 上是最优解。)~~(虽然可能是评测机进化了)~~ 首先还是要跑一遍 Dijkstra,建出最短路 DAG。 问题变成删除除了 $s$ 以外的一个点,使得 $s$ 无法到达的点数尽可能多。 注意我们只需要求最大值,所以没有必要把每个点删掉都求一遍。 首先,如果一个点入度为 $1$ 且它的入点不是 $s$,那么删它肯定不如删它的入点优。因为删掉它的入点后,它也无法被到达。也就是说一条“链”可以被缩成一个点。 那么做一遍拓扑排序,每次看所有入边的入点是否被缩成了同一个点。如果是,那么将当前点也缩进去。 缩完之后,每个点要么入度 $\ge 2$,要么入点是 $s$,要么自己就是 $s$。那么无论删掉哪个异于 $s$ 的点,其它点都能从 $s$ 到达。不能到达的只有当前点以及和它缩在一起的点。 对每个缩在一起的点集求大小最大值即可。 ```cpp #include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> PII; const int maxn=666666,mod=998244353; #define PB push_back #define MP make_pair #define lson o<<1,l,mid #define rson o<<1|1,mid+1,r #define FOR(i,a,b) for(int i=(a);i<=(b);i++) #define ROF(i,a,b) for(int i=(a);i>=(b);i--) #define MEM(x,v) memset(x,v,sizeof(x)) inline int read(){ int x=0,f=0;char ch=getchar(); while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return f?-x:x; } int n,m,s,el,head[maxn],to[maxn],nxt[maxn],w[maxn]; int el2,head2[maxn],to2[maxn],nxt2[maxn],deg[maxn]; int q[maxn],h,r,id[maxn],sz[maxn],ans,tmp[maxn]; ll dis[maxn]; struct node{ ll d; int u; bool operator<(const node &nd)const{return d>nd.d;} }; priority_queue<node> pq; inline void add(int u,int v,int ww){ to[++el]=v;nxt[el]=head[u];head[u]=el;w[el]=ww; } inline void add2(int u,int v){ to2[++el2]=v;nxt2[el2]=head2[u];head2[u]=el2;deg[v]++; } int main(){ n=read();m=read();s=read(); FOR(i,1,m){ int u=read(),v=read(),w=read(); add(u,v,w);add(v,u,w); } FOR(i,1,n) dis[i]=1e18; pq.push((node){dis[s]=0,s}); while(!pq.empty()){ int u=pq.top().u; ll d=pq.top().d; pq.pop(); if(dis[u]!=d) continue; for(int i=head[u];i;i=nxt[i]){ int v=to[i]; if(d+w[i]<dis[v]) pq.push((node){dis[v]=d+w[i],v}); } } FOR(u,1,n) for(int i=head[u];i;i=nxt[i]){ int v=to[i]; if(dis[u]+w[i]==dis[v]) add2(u,v); } q[h=r=1]=s; FOR(i,1,n) tmp[i]=i; while(h<=r){ int u=q[h++]; if(tmp[u]!=-1 && tmp[u]!=s) id[u]=tmp[u]; else id[u]=u; sz[id[u]]++; for(int i=head2[u];i;i=nxt2[i]){ int v=to2[i]; if(tmp[v]==v) tmp[v]=id[u]; else if(tmp[v]!=id[u]) tmp[v]=-1; if(!--deg[v]) q[++r]=v; } } FOR(i,1,n) if(i!=s) ans=max(ans,sz[i]); printf("%d\n",ans); } ```