P4700-[CEOI2011]Traffic【tarjan,dp】

1|0正题

题目链接:https://www.luogu.com.cn/problem/P4700


1|1题目大意

A×B的网格上有n个点,然后m条有向/无向边连接成平面图,求最左边每个点能到达的最右边点的数量。

1A,B109,1n3×105,1m9×105


1|2解题思路

突破点肯定是平面图,考虑假设对于左边两个点a,b,右边两个A,By坐标递增,显然如果a能走到B且不能走到A那么b一定不能走到A

也就是说每个点能到右边一定是一个区间上的点,先tarjan缩点一下dp出这个区间就好了。

需要注意的是如果一个右边的点无法被任何左边的点走到那么它不能被统计在区间里。

时间复杂度:O(nlogn)(排序)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<stack> using namespace std; const int N=3e5+10; int n,m,A,B,cnt,cot,pnt,bnt; int X[N],Y[N],p[N],b[N],l[N],r[N]; int dfn[N],low[N],col[N],in[N]; queue<int> q;stack<int> s; vector<int> G[N],T[N]; bool ins[N],v[N]; void tarjan(int x){ dfn[x]=low[x]=++cnt; s.push(x);ins[x]=1; for(int i=0;i<G[x].size();i++){ int y=G[x][i]; if(!dfn[y]){ tarjan(y); low[x]=min(low[x],low[y]); } else if(ins[y]) low[x]=min(low[x],dfn[y]); } if(dfn[x]==low[x]){ col[x]=++cot; while(s.top()!=x){ col[s.top()]=cot; ins[s.top()]=0;s.pop(); } ins[x]=0;s.pop(); } return; } void dfs(int x){ if(v[x])return;v[x]=1; for(int i=0;i<G[x].size();i++) dfs(G[x][i]); } void Topsort(){ for(int i=1;i<=cot;i++) if(!in[i])q.push(i); while(!q.empty()){ int x=q.front();q.pop(); for(int i=0;i<T[x].size();i++){ int y=T[x][i];in[y]--; l[y]=min(l[y],l[x]); r[y]=max(r[y],r[x]); if(!in[y])q.push(y); } } return; } bool cmp(int x,int y) {return Y[x]>Y[y];} int main() { scanf("%d%d%d%d",&n,&m,&A,&B); for(int i=1;i<=n;i++) scanf("%d%d",&X[i],&Y[i]); for(int i=1;i<=m;i++){ int x,y,k; scanf("%d%d%d",&x,&y,&k); G[x].push_back(y); if(k!=1)G[y].push_back(x); } for(int i=1;i<=n;i++) if(X[i]==0)dfs(i); for(int i=1;i<=n;i++){ if(X[i]==0)p[++pnt]=i; else if(X[i]==A&&v[i])b[++bnt]=Y[i]; } sort(b+1,b+1+bnt); for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i); for(int i=1;i<=cot;i++)l[i]=bnt+1,r[i]=0; for(int i=1;i<=n;i++) if(X[i]==A&&v[i]){ Y[i]=lower_bound(b+1,b+1+bnt,Y[i])-b; l[col[i]]=min(l[col[i]],Y[i]); r[col[i]]=max(r[col[i]],Y[i]); } for(int x=1;x<=n;x++) for(int i=0;i<G[x].size();i++){ int y=G[x][i]; if(col[x]==col[y])continue; T[col[y]].push_back(col[x]);in[col[x]]++; } Topsort(); sort(p+1,p+1+pnt,cmp); for(int i=1;i<=pnt;i++){ int x=col[p[i]]; if(!r[x]){puts("0");continue;} printf("%d\n",r[x]-l[x]+1); } return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/15344574.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(84)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示