• [CSP-S模拟测试]:午餐(贪心+最短路)


    题目传送门(内部题115)


    输入格式

      第一行两个正整数$n,m$。
      接下来$m$行,每行$4$个正整数$u_j,v_j,L_j,R_j$。
      接下来一行$n$个数,若第$i$个数为$1$,则$i$号同学最后学会了毒瘤算法;若第$i$个数为$-1$,则$i$号同学最后没有学会毒瘤算法。若第$i$个数为$0$,则不知道$i$号同学最后是否学会了毒瘤算法。


    输出格式

      若结果不可能出现,输出一行$Impossible$;否则,输出$m$行,第$j$行一个正整数表示第$j$条信息中的两名同学在哪一天共用午餐。


    样例

    样例输入1:

    4 3
    1 2 1 2
    2 3 1 2
    2 4 1 2
    1 0 1 -1

    样例输出1:

    2
    2
    1

    样例输入2:

    4 4
    1 2 1 2
    2 3 2 3
    2 4 1 2
    3 4 3 4
    1 0 1 -1

    样例输出2:

    Impossible


    数据范围与提示

      本题采用子任务评分。仅当你通过一个子任务下所有测试点时,你才能获得该子任务的分数。
      对于所有数据,$1leqslant n,mleqslant 200,000,1leqslant u_j,v_jleqslant n,u_j eq v_j,1leqslant L_ileqslant R_ileqslant 10^9$。
      $1.$($10$分)$n,mleqslant 12,R_ileqslant 3$。
      $2.$($15$分)$m=n-1$,且共用午餐的关系将所有同学连接到了一起。
      $3.$($15$分)不存在确定没有学会毒瘤算法的同学。
      $4.$($20$分)$n,mleqslant 2,000$。
      $5.$($40$分)没有特殊限制。


    题解

    在没有限制的情况下(不存在确定没有学会毒瘤算法的同学),显然贪心的选择最早学更优。

    那么现在我们考虑有没有学会毒瘤算法的同学的情况。

    不妨设$sec[i]$表示$i$点最早学会毒瘤算法的时间,那么没有学会毒瘤算法的同学付成$inf$即可。

    对于一个转移向这个同学的同学,其$sec$即为这条转移边的$l+1$,因为这两名同学可以在$l$时刻吃饭。

    这个过程可以用类似最短路的思想解决。

    剩余情况下尽可能早的吃饭一定更优,注意边界即可。

    时间复杂度:$Theta(nlog n)$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    struct rec{int nxt,to,l,r;}e[400001];
    struct node{int x,y,l,r;}b[200001];
    int head[200001],cnt;
    int n,m;
    int a[200001];
    int sec[200001],dis[200001];
    bool vis[200001];
    priority_queue<pair<int,int>>qs;
    priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>qt;
    void add(int x,int y,int l,int r){e[++cnt]=(rec){head[x],y,l,r};head[x]=cnt;}
    void Dij()
    {
    	while(qs.size())
    	{
    		int x=qs.top().second;
    		qs.pop();
    		if(vis[x])continue;
    		vis[x]=1;
    		for(int i=head[x];i;i=e[i].nxt)
    		{
    			if(e[i].r<sec[x]&&sec[e[i].to]<=e[i].l)
    			{
    				sec[e[i].to]=e[i].l+1;
    				qs.push(make_pair(sec[e[i].to],e[i].to));
    			}
    		}
    	}
    }
    void DIJ()
    {
    	memset(dis,0x3f,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	qt.push(make_pair(0,1));
    	dis[1]=0;
    	while(qt.size())
    	{
    		int x=qt.top().second;
    		qt.pop();
    		if(vis[x])continue;
    		vis[x]=1;
    		for(int i=head[x];i;i=e[i].nxt)
    		{
    			int maxn=max(max(sec[e[i].to],e[i].l),dis[x]);
    			if(maxn<dis[e[i].to]&&maxn<=e[i].r)
    			{
    				dis[e[i].to]=maxn;
    				qt.push(make_pair(dis[e[i].to],e[i].to));
    			}
    		}
    	}
    }
    int main()
    {
    	freopen("lunch.in","r",stdin);
    	freopen("lunch.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d%d%d",&b[i].x,&b[i].y,&b[i].l,&b[i].r);
    		add(b[i].x,b[i].y,b[i].l,b[i].r);
    		add(b[i].y,b[i].x,b[i].l,b[i].r);
    	}
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		if(a[i]==-1)
    		{
    			sec[i]=0x3f3f3f3f;
    			qs.push(make_pair(0x3f3f3f3f,i));
    		}
    	}
    	Dij();
    	DIJ();
    	for(int i=1;i<=n;i++)if(a[i]==1&&dis[i]==0x3f3f3f3f){puts("Impossible");return 0;}
    	for(int i=1;i<=m;i++)
    	{
    		if(a[b[i].x]==-1&&dis[b[i].y]<=b[i].l){puts("Impossible");return 0;}
    		if(a[b[i].y]==-1&&dis[b[i].x]<=b[i].l){puts("Impossible");return 0;}
    	}
    	for(int i=1;i<=m;i++)
    	{
    		if(a[b[i].x]==-1||a[b[i].y]==-1||b[i].r<max(dis[b[i].x],dis[b[i].y]))printf("%d
    ",b[i].l);
    		else printf("%d
    ",max(b[i].l,max(dis[b[i].x],dis[b[i].y])));
    	}
    	return 0;
    }
    

    rp++

  • 相关阅读:
    Kibana
    nginx
    Installing Node.js and Express on Ubuntu
    Boost test vs2013 fatal error C1001
    最小二乘法拟合直线
    RvmTranslator for Linux
    RvmTranslator7.1
    OpenCASCADE直线与平面求交
    OpenCASCADE点向平面投影
    RvmTranslator7.0-OBJ
  • 原文地址:https://www.cnblogs.com/wzc521/p/11782772.html
Copyright © 2020-2023  润新知