zoukankan      html  css  js  c++  java
  • P4700-[CEOI2011]Traffic【tarjan,dp】

    正题

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


    题目大意

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

    (1leq A,Bleq 10^9,1leq nleq 3 imes 10^5,1leq mleq 9 imes 10^5)


    解题思路

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

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

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

    时间复杂度:(O(nlog n))(排序)


    code

    #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
    ",r[x]-l[x]+1);
    	}
    	return 0;
    }
    
  • 相关阅读:
    ViewPager留出边 显示左右两边的视图
    Retrofit 2.0 上传文件
    android一个app打开另一个app的指定页面
    Java多线程消费者、生产者的基本思路
    Android 8.0+ 更新安装apk失败的问题
    Android 8.0+ 通知不显示的适配
    android 7.0+ FileProvider 访问隐私文件 相册、相机、安装应用的适配
    android 6.0+ 动态权限 拒绝不再询问后跳转设置应用详情页面
    ViewPager中Fragment的重复创建、复用问题
    Android源码学习(2) Handler之Looper
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15344574.html
Copyright © 2011-2022 走看看