【10.27校内测试】【可删堆+拓排】

Solution

有向图要找最长路径的话,可以想到拓扑序转移。正反跑两边处理出每个点离起点和终点的最大值。访问每条边就能统计出经过每条边最长路径的长度。

问题是怎么统计出删除每个点的影响?

拓扑排序后,可以发现,删除层数靠后的点会对前面产生影响,因为此时想统计前面的边存在的最长路就不能判掉经过这个点的路径,所以只能按拓扑序从前往后删点。

这里直接说做法吧,维护一个大根堆,储存当前枚举到的最长路径,首先把每个点离终点的最大值推入堆中。每枚举删除一个点,就把它对前面点有影响的路径删掉,更新答案后再把它对后面的路径加入堆中,做完所有点即可。

但是堆不能直接实现制定元素删除操作,所以要用可删堆QAQ

其实就是两个堆,一个维护当前堆,一个维护待删除的元素,每次删除就往第二个堆中加入元素,实际操作是在取出过程中实现的,如果当前两个堆顶元素相同时,就删除两个堆顶即可。

%%%$jzy$大佬码风新奇,我等一般人只能仰望%%%

Code

#include<bits/stdc++.h>
#define RG register
using namespace std;
inline char nc()
{
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x) {
    x = 0; int t = 1; char ch = nc();
    while(ch > ‘9‘ || ch < ‘0‘) { if(ch == ‘-‘)    t = -1; ch = nc(); }
    while(ch >= ‘0‘ && ch <= ‘9‘) { x = x * 10 + ch - ‘0‘; ch = nc(); }
    x *= t;
}

struct Node {
    int v, nex;
} Edge[500005], Edge_rz[500005];

int stot_rz = 0, h_rz[100005], stot, h[100005];
void add(int u, int v) {
    Edge[++stot] = (Node) {v, h[u]};
    h[u] = stot;
    Edge_rz[++stot_rz] = (Node) {u, h_rz[v]};
    h_rz[v] = stot_rz;
}

class Heap {
    private:
        priority_queue < int > q1;
        priority_queue < int > q2;
    public:
        inline void init() {
            while(!q1.empty())    q1.pop();
            while(!q2.empty())    q2.pop();
        }
        inline void push(int x) {
            q1.push(x);
        }
        inline void del(int x) {
            q2.push(x);
        }
        inline int top() {
            while(!q2.empty() && q1.top() == q2.top()) {
                q1.pop();    q2.pop();
            }
            return q1.top();
        }
} Q;

int in[100005], q[100005], st[100005], ed[100005], ans, id, n, m;
int main() {
    freopen("johnny.in", "r", stdin);
    freopen("johnny.out", "w", stdout);
    int T;
    read(T);
    while(T --) {
        memset(h, 0, sizeof(h));
        memset(h_rz, 0, sizeof(h_rz));
        stot = 0, stot_rz = 0; int t = 0, hi = 1;
        memset(q, 0, sizeof(q));
        memset(in, 0, sizeof(in));
        memset(st, 0, sizeof(st));
        memset(ed, 0, sizeof(ed));
        ans = 0x3f3f3f3f, id = 0;
        Q.init();
        read(n);    read(m);
        while(m --) {
            int u, v;
            read(u);    read(v);
            add(u, v);
            in[v] ++;
        }
        for(int i = 1; i <= n; i ++)
            if(!in[i])    q[++t] = i;
        while(hi <= t) {
            int u = q[hi ++];
            for(RG int i = h[u]; i; i = Edge[i].nex) {
                int v = Edge[i].v;
                if((-- in[v]) == 0)    q[++t] = v;
            }
        }
        for(RG int i = 1; i <= n; i ++) {
            int u = q[i];
            for(RG int j = h[u]; j; j = Edge[j].nex) {
                int v = Edge[j].v;
                st[v] = max(st[v], st[u] + 1);
            }
        }
        for(RG int i = n; i >= 1; i --) {
            int u = q[i];
            for(RG int j = h_rz[u]; j; j = Edge_rz[j].nex) {
                int v = Edge_rz[j].v;
                ed[v] = max(ed[v], ed[u] + 1);
            }
        }
        for(int i = 1; i <= n; i ++)    Q.push(ed[i]);
        for(RG int i = 1; i <= n; i ++) {
            int u = q[i];
            for(int j = h_rz[u]; j; j = Edge_rz[j].nex) {
                int v = Edge_rz[j].v;
                Q.del(st[v] + ed[u] + 1);
            }
            Q.del(ed[u]);
            int now = Q.top();
            if(now < ans)    ans = now, id = u;
            else if(now == ans)    id = min(id, u);
            for(RG int i = h[u]; i; i = Edge[i].nex) {
                int v = Edge[i].v;
                Q.push(st[u] + ed[v] + 1);
            }
            Q.push(st[u]);
        }
        printf("%d %d\n", id, ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/wans-caesar-02111007/p/9866668.html

时间: 2024-08-29 23:44:05

【10.27校内测试】【可删堆+拓排】的相关文章

【10.17校内测试】【二维数位DP】【博弈论/预处理】【玄学(?)DP】

Solution 几乎是秒想到的水题叻! 异或很容易想到每一位单独做贡献,所以我们需要统计的是区间内每一位上做的贡献,就是统计区间内每一位是1的数的数量. 所以就写数位dp辣!(昨天才做了数字统计不要太作弊啊!) Code #include<bits/stdc++.h> #define LL long long #define mod 1000000007 using namespace std; inline void read(LL &x) { x = 0; char ch = g

【10.22校内测试】【二分】【二分图】【很像莫队的乱搞/树状数组】

Solution 谁能想到这道题卡读入??还卡了70pts??? 二分+$n^2$check就行了 Code #include<bits/stdc++.h> using namespace std; int n, m; int sum[2005][2005]; void read(int &x) { x = 0; char ch = getchar(); while(ch > '9' || ch < '0') ch = getchar(); while(ch >= '

【10.5校内测试】【DP】【概率】

转移都很明显的一道DP题.按照不优化的思路,定义状态$dp[i][j][0/1]$表示吃到第$i$天,当前胃容量为$j$,前一天吃(1)或不吃(0)时能够得到的最大价值. 因为有一个两天不吃可以复原容量的定义,所以需要前一天的状态. 而注意,容量表示的是当前第$i$天吃之前的容量. 然后考虑压缩空间,将天数滚动.要注意的是滚动过后$now$指向的是$i$后一天的状态,因此刷表更新. #include<bits/stdc++.h> using namespace std; int n, m; i

【10.7校内测试】【队列滑窗】【2-sat】【贪心+栈二分+线段树(noip模拟好题)】【生日祭!】

比较好想的一道题,直接用队列滑窗,因为扫一遍往队列里加东西时,改变的只有一个值,开桶储存好就行了! #include<bits/stdc++.h> using namespace std; int n, k, r; inline int min(int a, int b) { return a > b ? b : a; } inline int max(int a, int b) { return a > b ? a : b; } int sum[200005], q[200005

10.27 模拟赛

这一次终极被吊打 甚至没进前十 T2 最后改错 T3 没写正解 T1 elim 题目大意: n 行 m 列的游戏棋盘,一行或一列上有连续 三个或更多的相同颜色的棋子时,这些棋子都被消除 当有多处可以被消除时,这些地方的棋子将同时被消除 求消除后的棋盘 思路: sb模拟 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cm

10.27练习题 [POI2008]Blockade

10.27练习题 [POI2008]Blockade KONO题面哒! 问题描述 某地区有n个城镇,一些城镇之间由无向边连接.每两个城镇之间至多只有一条直接连接的道路.人们可以从任意一个城镇直接或间接到达另一个城镇.每个城镇都有一个镇长.该地区正在进行镇长互访活动,每个镇长都要拜访其他所有镇长一次. 所以,计划会安排有一共n(n-1)次访问活动. 不幸的是,一个程序员总罢工正在进行中.作为抗议行动,程序员们计划封锁一些城镇,阻止人们进入,离开或者路过那里.他们正在讨论选择哪些城镇会导致最严重的后

10.23 linux任务计划cron10.24chkconfig工具10.25 systemd管理服务10.26 unit介绍 10.27 target介绍

- 10.23 linux任务计划cron - 10.24 chkconfig工具 - 10.25 systemd管理服务 - 10.26 unit介绍 - 10.27 target介绍 - 扩展 1. anacron http://blog.csdn.net/strikers1982/article/details/4787226  2. xinetd服(默认机器没有安装这个服务,需要yum install xinetd安装) http://blog.sina.com.cn/s/blog_46

一周随笔--15.10.27

一周新知识点记录(15.10.27) 一.不规则按钮OBShapedButton 常规按钮都是一个矩形区域,即使设置了按钮layer的cornerRadious,能响应点击事件的依旧是整个矩形区域. OBShapedButton是开源的第三方库,直接继承自UIButton,直接使用即可.它的响应区域只限定在button的图片或者背景图片区域,周围空出的区域无法响应. 二.sendActionsForControlEvents UIButton的实例方法,通过代码手动发送按钮的点击事件触发按钮的响

背水一战 Windows 10 (27) - 控件(文本类): TextBlock

原文:背水一战 Windows 10 (27) - 控件(文本类): TextBlock [源码下载] 作者:webabcd 介绍背水一战 Windows 10 之 控件(文本类) TextBlock 示例1.TextBlock 的示例 1Controls/TextControl/TextBlockDemo1.xaml <Page x:Class="Windows10.Controls.TextControl.TextBlockDemo1" xmlns="http://