题目链接:https://www.luogu.com.cn/problem/P4700
A×B的网格上有n个点,然后m条有向/无向边连接成平面图,求最左边每个点能到达的最右边点的数量。
1≤A,B≤109,1≤n≤3×105,1≤m≤9×105
突破点肯定是平面图,考虑假设对于左边两个点a,b,右边两个A,B,y坐标递增,显然如果a能走到B且不能走到A那么b一定不能走到A。
也就是说每个点能到右边一定是一个区间上的点,先tarjan缩点一下dp出这个区间就好了。
需要注意的是如果一个右边的点无法被任何左边的点走到那么它不能被统计在区间里。
时间复杂度:O(nlogn)(排序)
#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__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .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语句:使用策略模式优化代码结构