[CSP校内集训]pestc(拓扑排序)

题意

给一个边带权的有向图,可以花费边权使得一条边反向;通过翻转边让原图变成一个DAG,要求是所有花费中的最大值最小\(,(n,m\leq 200000)\),保证无重边和自环

解法1

考场上没看出来性质,于是口胡了一个乱搞做法

连好边后直接对原图进行一遍拓扑排序,由于原图不是DAG,所以会有无法入队的环存在;如果当前队列为空而有点没有被遍历到,那么就强行选择一个点将连向它的边翻转;
具体的,我们选择\((max(\) 连向\(i\)的边 \())\)最小的\(i\),由于翻转了连向\(i\)的边,需要将\(ans\)与\((max(\) 连向i的边 \())\)取最大值

维护max值用大根堆,维护max值最小的点用set,虽说复杂度为\(O(nlogn)\)但并不好写(为什么还跑的比正解快啊qwq)

Code

#include<bits/stdc++.h>
#define N 200005
#define Min(x,y) ((x)<(y)?(x):(y))
#define Max(x,y) ((x)>(y)?(x):(y))
using namespace std;
typedef long long ll;
int n,m,rd[N],ans=0;
bool vis[N];
struct Edge
{
    int next,to,dis;
}edge[N<<1];int head[N],cnt;
void add_edge(int from,int to,int dis)
{
    edge[++cnt].next=head[from];
    edge[cnt].to=to;
    edge[cnt].dis=dis;
    head[from]=cnt;
}
priority_queue<int> mx[N];//一个大根堆维护指向一个点最大的边权
priority_queue<int> lz[N];//一个大根堆懒删除
set< pair<int,int> > s;//一个set维护最大边权最小的点编号 

template <class T>
void read(T &x)
{
    char c; int sign=1;
    while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
}
void topo()//一次拓扑
{
    queue<int> q;
    for(int i=1;i<=n;++i)
      if(!rd[i]) q.push(i);
        else s.insert(make_pair(mx[i].top(),i));
    int rest=n;
    while(rest)
    {
        --rest;
        int v,u;
        if(q.empty())//成环了
        {
            v=s.begin()->first,u=s.begin()->second;
            while(!s.empty()&&vis[u])
            {
                s.erase(make_pair(v,u));
                v=s.begin()->first;u=s.begin()->second;
            }
            ans=Max(ans,v);
        }
        else {u=q.front();q.pop();}
        vis[u]=1;
        for(int i=head[u];i;i=edge[i].next)
        {
            int v=edge[i].to;
            if(--rd[v]==0 && !vis[v]) {q.push(v);vis[v]=1;continue;}
            //如果没有入队就更新
            lz[v].push(edge[i].dis);//删除这条边
            s.erase(make_pair(mx[v].top(),v));//更新最大值
            while(!lz[v].empty()&&mx[v].top()==lz[v].top())
            {
                mx[v].pop();
                lz[v].pop();
            }
            s.insert(make_pair(mx[v].top(),v));
        }
    }
}
int main()
{
    freopen("pestc.in","r",stdin);
    freopen("pestc.out","w",stdout);
    read(n);read(m);
    for(int i=1;i<=m;++i)
    {
        int x,y,z;
        read(x);read(y);read(z);
        add_edge(x,y,z);
        mx[y].push(z);
        ++rd[y];
    }
    topo();
    cout<<ans<<endl;
    return 0;
}

解法2

题解做法

显然答案具有单调性,二分一个\(mid\),将\(\leq mid\)的边全部删掉,如果此时的图是一个DAG那么就返回true

正确性:由于此时的图是一个DAG,而\(\leq mid\)的边方向可以随便定,从dfn小的点指向dfn大的点即可形成一个新的DAG



原题CF1100E Andrew and Taxi还需要输出翻转边的方案,用解法2通过比较dfn可以很容易输出方案;而解法1还需要再在大根堆中记录每条边的编号emmm

原文地址:https://www.cnblogs.com/Chtholly/p/11805034.html

时间: 2024-10-03 23:13:56

[CSP校内集训]pestc(拓扑排序)的相关文章

[CSP校内集训]rank

题意 给出一个字符串后缀排序之后的数组\(sa_i\),求原字符串(字典序最小),无解输出-1 思路 显然从\(rk_1\)开始填字符是可以保证字符单调不降的 找到\(sa\)值相邻的两个位置,现在需要知道\(rk_i\)和\(rk_{i+1}\)是否可以填相邻字符:当它们填相同字符时需要比较后一位,如果相对关系相同则可行(因为后一位默认已经成立) 举个栗子:\(4,2,3,1\),查看4能不能和3填同一个字符,则判断后一位2和1:而\(4>3 \&\& 2>1\),所以可以相

[CSP校内集训]矩形面积交(树状数组)

题意 给\(n\)个互不相交的矩形,再给\(m\)个询问,每次给一个矩形求它与这\(n\)个矩形的面积交 思路 自己写的太丑了导致DEBUG了一个半小时qwq 一对矩形的交可以拆分成二维前缀和形式下的矩形的交,于是变成判断16次矩形的交(不想画图...只想口胡) 这些矩形都有\(x_0=0,y_0=0\),即左下角为坐标原点,于是一个矩形可以只用右上角的坐标表示: 对于一个询问的矩形\((x,y)\)和另一个矩形\((x_i,y_i)\),它们的交为\(min(x,x_i)\times min(

[CSP校内集训]贪吃蛇(阿尔法-贝塔剪枝)

题目 有两条蛇(1号蛇和2号蛇)在n行m列的地图上,地图上有障碍物.一条蛇碰到蛇身/障碍物/边界就会死.蛇身会不断长长--可以理解为蛇尾位置不会变,蛇只会向前伸展不会缩尾巴.两条蛇都绝顶聪明,如果自己能赢,一定会尽量快地赢;如果自己会输,一定会死得尽量晚.给出初始局面,两蛇轮流走,每次可以且必须向上下左右移动一格.1号蛇先走,请告诉我谁会在多少回合时赢.\((n,m\leq 20)\)且\(0\)的数量不超过\(50\) \(\alpha - \beta\)剪枝 AlphaBeta剪枝算法是一个

[CSP校内集训]attack(DAG支配树)

题意 给一个DAG,多次询问,每次给定\(k\)个点,求1到这些点的必经点的交集大小 思路 支配树裸题,建好DAG的支配树后\(k\)个点LCA的深度即为答案 Code #include<bits/stdc++.h> #define N 100005 using namespace std; int n,m,q; int rd[N],f[N][18],dep[N]; struct Edge { int next,to; }edge[N<<1],edge1[N<<1];i

[CSP校内集训]tree(期望DP)

题意 给一颗树,从1节点出发,走每条边的概率相同且耗时为1,求每个点第一次被遍历到的期望时间(\(t_1=1\)) 思路 在树上只有两种移动方式:从儿子到父亲,从父亲到儿子 假设从\(rt\)走到\(v\)的期望代价为\(dow_i\),从\(i\)走到\(rt\)的期望代价为\(val_i\) 假设从\(rt\)转移到\(v\),\(rt\)的度数为\(k\),\(rt\)的父亲为\(fa\),则: \[dow_v = \frac{1}{k} + \sum_{son}^{son\neq v}

暑假集训之专题----拓扑排序题解

第一单: Problem A Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submission(s) : 26   Accepted Submission(s) : 5 Problem Description ACM-DIY is a large QQ group where many excellent acmers get together. It is so h

寒假集训日志(二)——最小生成树,拓扑排序,欧拉回路,连通路

今天学的内容挺多的. (一)首先说最小生成树,两种算法: 1.Kruskal算法( 将边排序,然后再选,关键在于检查是否连通,使用并查集) 2.Prim算法(使用点集,有点类似与最短路的算法) 第一题是并查集算法的使用: A - The Suspects Time Limit:1000MS     Memory Limit:20000KB     64bit IO Format:%I64d & %I64u Submit Status Description 严重急性呼吸系统综合症( SARS),

【CSP模拟赛】益智游戏(最短路&amp;拓扑排序)

题目描述 小P和小R在玩一款益智游戏.游戏在一个正权有向图上进行. 小P 控制的角色要从A 点走最短路到B 点,小R 控制的角色要从C 点走最短路到D 点. 一个玩家每回合可以有两种选择,移动到一个相邻节点或者休息一回合. 假如在某一时刻,小P 和小R 在相同的节点上,那么可以得到一次特殊奖励,但是在每 个节点上最多只能得到一次. 求最多能获得多少次特殊奖励 输入格式 第一行两个整数n,m 表示有向图的点数和边数. 接下来m 行每行三个整数xi,yi,li,表示从xi 到yi 有一条长度为li

hiho一下 第四十八周 拓扑排序&#183;二【拓扑排序的应用 + 静态数组 + 拓扑排序算法的时间优化】

题目1 : 拓扑排序·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho所在学校的校园网被黑客入侵并投放了病毒.这事在校内BBS上立刻引起了大家的讨论,当然小Hi和小Ho也参与到了其中.从大家各自了解的情况中,小Hi和小Ho整理得到了以下的信息: 校园网主干是由N个节点(编号1..N)组成,这些节点之间有一些单向的网路连接.若存在一条网路连接(u,v)链接了节点u和节点v,则节点u可以向节点v发送信息,但是节点v不能通过该链接向节点u发送信息. 在刚