P4700 [CEOI2011] Traffic 题解

发布时间 2024-01-06 08:18:13作者: Pengzt

P4700

简单的,但是考试的时候没看到是平面图,就只想到了缩点后 DAG 判断能到达哪些点。用 bitset 维护做到 \(\mathcal{O}(\frac{nm}{w})\) 的时空复杂度,但是空间会炸。

由于这个图是平面图,稍微推一下就可以知道所有能它最终所能到达的点一定是从西侧出发所能到达的东侧点的点集中按 \(y\) 排序后的一段区间。

然后就很简单了,在读入时将 \(a_i\) 排序后重编号再进行操作就很方便了,最后直接在 DAG 的反图上 dp。具体地,令 \(gl_i\)\(gr_i\) 表示缩点后编号为 \(i\) 的强连通分量所能到达的 \(y\) 最小的点和 \(y\) 最大的点,然后对所有连出的点更新一下即可。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int N=3e5+10,inf=1e9;
int n,m,A,B;
int a[N],au[900010],av[900010],aw[900010],ori[N];
vector<int> g[N];
struct node{int x,y,id;} ad[N];
int head[N],cnt_e=1;
struct edge{int v,nxt;} e[1800010];
void adde(int u,int v,int w=2){
	e[++cnt_e]=(edge){v,head[u]};
	head[u]=cnt_e;
	if(w==2)adde(v,u,1);
}
int dfc,dfn[N],low[N],stk[N],tp,vis[N],cs,bel[N],gl[N],gr[N];
void dfs(int u){
	dfn[u]=low[u]=++dfc;vis[stk[++tp]=u]=1;
	for(int i=head[u],v;i;i=e[i].nxt)if(!dfn[v=e[i].v])dfs(v),low[u]=min(low[u],low[v]);else if(vis[v])low[u]=min(low[u],dfn[v]);
	if(low[u]==dfn[u]){
		int v=0;cs++;
		do{bel[v=stk[tp--]]=cs;vis[v]=0;if(a[v]==1)gl[cs]=min(gl[cs],v),gr[cs]=max(gr[cs],v);}while(v!=u);
	}
}
int deg[N],s[N],ac;queue<int> q;
pii ans[N],ne[N];
int main(){
	cin>>n>>m>>A>>B;
	for(int i=1;i<=n;gl[i]=1e9,i++)cin>>ad[i].x>>ad[i].y,ad[i].id=i;
	sort(ad+1,ad+n+1,[](node a,node b){return a.y<b.y;});
	for(int i=1;i<=n;i++)a[i]=(ad[i].x==A?1:(ad[i].x==0?0:2)),ori[ad[i].id]=i;
	for(int i=1;i<=m;i++)cin>>au[i]>>av[i]>>aw[i],adde(au[i]=ori[au[i]],av[i]=ori[av[i]],aw[i]);
	for(int i=1;i<=n;i++)if(!dfn[i]&&!a[i])dfs(i);
	for(int i=1,u,v;i<=m;i++)if(bel[u=au[i]]!=bel[v=av[i]]&&bel[u]&&bel[v])g[bel[v]].push_back(bel[u]),deg[bel[u]]++;
//	for(int i=1;i<=cs;i++)for(int j:g[i])cout<<"Edge: "<<i<<" "<<j<<"\n";
	for(int i=1;i<=cs;i++)if(!deg[i])q.push(i);
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int v:g[u]){
			gl[v]=min(gl[v],gl[u]),gr[v]=max(gr[v],gr[u]);
			if(!--deg[v])q.push(v);
		}
	}
	for(int i=1;i<=n;i++)s[i]=s[i-1]+(a[i]==1&&dfn[i]);
	for(int i=1;i<=n;i++)if(!a[i]){
		int j=bel[i];
//		cout<<i<<" "<<gl[j]<<" "<<gr[j]<<"\n";
		if(gl[j]!=inf)ans[++ac]=pii(ad[i].y,s[gr[j]]-s[gl[j]-1]);else ans[++ac]=pii(ad[i].y,0);
	}
	sort(ans+1,ans+ac+1,greater<pii>());
	for(int i=1;i<=ac;i++)cout<<ans[i].second<<"\n";
	return 0;
}