• 【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;
    }
    
  • 相关阅读:
    20145216 史婧瑶《信息安全系统设计基础》第一周学习总结
    20145216史婧瑶《信息安全系统设计基础》第0周学习总结
    20145216《java程序设计》课程总结
    20145216史婧瑶《Java程序设计》第10周学习总结
    20145216史婧瑶《Java程序设计》第五次实验报告
    20145216史婧瑶《Java程序设计》第四次实验报告
    20145216史婧瑶《Java程序设计》第9周学习总结
    20145216史婧瑶《Java程序设计》第三次实验报告
    20145216史婧瑶《Java程序设计》第8周学习总结
    20145220韩旭飞第五周博客
  • 原文地址:https://www.cnblogs.com/stoorz/p/14426273.html
Copyright © 2020-2023  润新知