hdoj 5638 Toposort 【线段树 维护 拓扑序】

题目链接:hdoj 5638 Toposort

题意:给定 n 个点和 m 条边的有向图,你可以删掉 k 条边,让你找到字典序最小的拓扑序列。

思路:记录入度,建在线段树上。下面就是查询 <=k 的前提下最小的节点u,然后更新信息即可。

AC 代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define CLR(a, b) memset(a, (b), sizeof(a))
#define ll o<<1
#define rr o<<1|1
using namespace std;
typedef long long LL;
const int MAXN = 1e5+10;
const int MAXM = 2*1e6+10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int MOD = 1e9+7;
struct Edge{
    int from, to, next;
};
Edge edge[MAXM];
int head[MAXN], edgenum;
int in[MAXN];
void init() {CLR(head, -1); edgenum = 0;}
void addEdge(int u, int v)
{
    Edge E = {u, v, head[u]};
    edge[edgenum] = E;
    head[u] = edgenum++;
}
struct Tree{
    int l, r, Min;
};
Tree tree[MAXN<<2];
void PushUp(int o) {
    tree[o].Min = min(tree[ll].Min, tree[rr].Min);
}
void Build(int o, int l, int r)
{
    tree[o].l = l; tree[o].r = r;
    if(l == r)
    {
        tree[o].Min = in[l];
        return ;
    }
    int mid = (l + r) >> 1;
    Build(ll, l, mid); Build(rr, mid+1, r);
    PushUp(o);
}
void Update(int o, int pos, int val)
{
    if(tree[o].l == tree[o].r)
    {
        tree[o].Min = val;
        return ;
    }
    int mid = (tree[o].l + tree[o].r) >> 1;
    if(pos <= mid) Update(ll, pos, val);
    else Update(rr, pos, val);
    PushUp(o);
}
int Query(int o, int k)
{
    if(tree[o].l == tree[o].r)
        return tree[o].l;
    if(tree[ll].Min <= k) return Query(ll, k);
    else return Query(rr, k);
}
int main()
{
    int t; scanf("%d", &t);
    while(t--)
    {
        int n, m, k; scanf("%d%d%d", &n, &m, &k);
        init();
        for(int i = 1; i <= n; i++) in[i] = 0;
        for(int i = 0; i < m; i++)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            addEdge(u, v); in[v]++;
        }
        Build(1, 1, n); LL ans = 0;
        for(int i = 1; i <= n; i++)
        {
            int u = Query(1, k); k -= in[u]; in[u] = INF; Update(1, u, INF);
            for(int j = head[u]; j != -1; j = edge[j].next)
            {
                int v = edge[j].to;
                if(in[v] == INF) continue;
                Update(1, v, --in[v]);
            }
            ans = (ans + 1LL*i*u%MOD) % MOD;
        }
        cout << ans << endl;
    }
    return 0;
}

你可能感兴趣的:(线段树,拓扑排序)