• 【YbtOJ#603】情报传递


    题目

    题目链接:https://www.ybtoj.com.cn/contest/120/problem/2

    (n,m,tleq 10^5)

    思路

    UPD:卡过去了,把每次循环里邻接表去掉了,按照转移顺序扔进了一个数组里,这样内存连续寻址快。
    这题卡常卡的就 NM 离谱。。。clock 过去的。
    显然对于第一类要求,按照它的要求连边就是最优的,所以我们只需要判断按照这样的方法连边能不能满足第二类要求即可。
    tarjan 把强连通分量缩一下,问题转化到这张 DAG 上。用 bitset 优化 DAG 传递闭包就可以做到时空 (O(frac{n^2}{omega})),可以得到 (60) 分。
    考虑压缩空间,直接把点双分块,每次把一个块内的点双拿去跑拓扑,这样时间复杂度依然是 (O(frac{n^2}{omega})),空间只需要 (O(frac{nT}{omega})) 了。其中 (K) 是分的块的数量。
    然后 tm 卡常卡死了。用 clock() 过了。

    代码

    #include <bits/stdc++.h>
    #define reg register
    using namespace std;
    typedef long long ll;
    
    const int N=100010,lim=63;
    int head[N],dfn[N],bel[N],low[N],U[N],V[N],X[N],Y[N];
    int n,m,Q,tot,cnt;
    bool vis[N];
    ll s[N];
    stack<int> st;
    
    struct node
    {
    	int x,y;
    }b[N];
    
    bool cmp(node x,node y)
    {
    	return x.y<y.y;
    }
    
    int read()
    {
    	int d=0; char ch=getchar();
    	while (!isdigit(ch)) ch=getchar();
    	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
    	return d;
    }
    
    void write(int x)
    {
    	if (x>9) write(x/10);
    	putchar(x%10+48);
    }
    
    struct edge
    {
    	int next,to;
    }e[N];
    
    void add(int from,int to)
    {
    	e[++tot]=(edge){head[from],to};
    	head[from]=tot;
    }
    
    void tarjan(int x)
    {
    	dfn[x]=low[x]=++tot;
    	st.push(x); vis[x]=1;
    	for (reg int i=head[x];~i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if (!dfn[v])
    		{
    			tarjan(v);
    			low[x]=min(low[x],low[v]);
    		}
    		else if (vis[v])
    			low[x]=min(low[x],dfn[v]);
    	}
    	if (low[x]==dfn[x])
    	{
    		int y; cnt++;
    		do {
    			y=st.top(); st.pop();
    			vis[y]=0; bel[y]=cnt;
    		} while (y!=x);
    	}
    }
    
    int main()
    {
    	freopen("gplt.in","r",stdin);
    	freopen("gplt.out","w",stdout);
    	memset(head,-1,sizeof(head));
    	n=read(); m=read();
    	for (reg int i=1;i<=m;i++)
    	{
    		U[i]=read(); V[i]=read();
    		add(U[i],V[i]);
    	}
    	tot=0;
    	for (reg int i=1;i<=n;i++)
    		if (!dfn[i]) tarjan(i);
    	memset(head,-1,sizeof(head)); tot=0;
    	for (reg int i=1;i<=m;i++)
    		if (bel[U[i]]!=bel[V[i]])
    			add(bel[V[i]],bel[U[i]]);
    	Q=read(); tot=0;
    	for (reg int i=1;i<=Q;i++)
    		b[i].x=bel[read()],b[i].y=bel[read()];
    	sort(b+1,b+1+Q,cmp);
    	for (reg int i=1;i<=cnt;i++)
    		for (reg int j=head[i];~j;j=e[j].next)
    			X[++tot]=e[j].to,Y[tot]=i;
    	for (reg int k=1,l=1;(k-1)*lim<cnt;k++)
    	{
    		int L=(k-1)*lim+1,R=min(k*lim,cnt);
    		for (reg int i=1;i<=cnt;i++)
    			s[i]=(L<=i && R>=i)?(1LL<<(i-L)):0;
    		for (reg int i=1;i<=tot;i++) s[X[i]]|=s[Y[i]];
    		for (;l<=Q && b[l].y<=R;l++)
    			if (s[b[l].x]&(1LL<<(b[l].y-L)))
    				return printf("NO"),0;
    	}
    	printf("YES
    %d
    ",m);
    	for (reg int i=1;i<=m;i++)
    		write(U[i]),putchar(32),write(V[i]),putchar(10);
    	return 0;
    }
    
  • 相关阅读:
    bzoj 2038 [2009国家集训队]小Z的袜子(hose)
    【NOIP2014模拟11.1B组】吴传之火烧连营
    【NOIP2014模拟11.1B组】蜀传之单刀赴会
    phpmystudy:mysql启动失败
    英文漏洞报告解读(一)——PHP 5.4.x < 5.4.32 Multiple Vulnerabilities
    brupsuit Compare 模块及其应用场景
    Android实现Banner界面广告图片循环轮播(包括实现手动滑动循环)
    android ViewPager实现的轮播图广告自定义视图,网络获取图片和数据
    Android首页轮播图直接拿来用
    java 调用webservice的各种方法总结
  • 原文地址:https://www.cnblogs.com/stoorz/p/14426273.html
Copyright © 2020-2023  润新知