HDU 5638 Toposort 线段树+贪心

Posted shuguangzw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 5638 Toposort 线段树+贪心相关的知识,希望对你有一定的参考价值。

题意:bc round 74

分析:

参考下普通的用堆维护求字典序最小拓扑序, 用某种数据结构维护入度小于等于k的所有点, 每次找出编号最小的, 并相应的减少k即可.

这个数据结构可以用线段树, 建立一个线段树每个节点[l,r]维护编号从ll到rr的所有节点的最小入度, 查询的时候只需要在线段树上二分,

找到最小的x满足入度小于等于k.

复杂度O((n+m)logn)

技术分享
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
#include <cmath>
using namespace std;
typedef long long LL;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const int N=1e5+5;
int d[N],o[N<<2],head[N],p;
struct Edge
{
    int v,next;
}edge[N*2];
void add(int u,int v)
{
    edge[p].v=v;
    edge[p].next=head[u];
    head[u]=p++;
}
void pushup(int rt)
{
    o[rt]=min(o[rt*2],o[rt*2+1]);
}
void build(int rt,int l,int r)
{
    if(l==r)
    {
        o[rt]=d[l];
        return;
    }
    int mid=(l+r)>>1;
    build(rt*2,l,mid);
    build(rt*2+1,mid+1,r);
    pushup(rt);
}
void update(int rt,int l,int r,int pos)
{
    if(l==r)
    {
        o[rt]=d[l];
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)update(rt*2,l,mid,pos);
    else update(rt*2+1,mid+1,r,pos);
    pushup(rt);
}
int query(int rt,int l,int r,int c)
{
   if(l==r)
     return l;
   int mid=(l+r)>>1;
   if(o[rt*2]<=c)return query(rt*2,l,mid,c);
   else return query(rt*2+1,mid+1,r,c);
}
int main()
{
    int T,n,m,k;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&k);
        memset(head,-1,sizeof(head));
        memset(d,0,sizeof(d));
        p=0;
        for(int i=0;i<m;++i)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            ++d[v];
        }
        build(1,1,n);
        LL ans=0;
        for(int i=1;i<=n;++i)
        {
            LL x=query(1,1,n,k),y=i;
            ans=(ans+x*y%mod)%mod;
            k-=d[x];
            d[x]=INF;
            update(1,1,n,x);
            for(int j=head[x];~j;j=edge[j].next)
            {
               int v=edge[j].v;
               if(d[v]==INF)continue;
               --d[v];
               update(1,1,n,v);
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
}
View Code

 

以上是关于HDU 5638 Toposort 线段树+贪心的主要内容,如果未能解决你的问题,请参考以下文章

HDU 6047 Maximum Sequence(贪心+线段树)

HDU 2795 Billboard (线段树+贪心)

HDU 5338(ZZX and Permutations-用线段树贪心)

hdu 1257 最少拦截系统(动态规划 || 构造法-贪心 || 线段树)

HDU4825 Xor Sum(贪心+Trie树)

APIO 2012 守卫 | 差分 / 线段树 + 贪心