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;
}

时间: 2024-12-10 13:11:10

HDU 5638 Toposort 线段树+贪心的相关文章

HDU 2795 Billboard (线段树+贪心)

手动博客搬家:本文发表于20170822 21:30:17, 原地址https://blog.csdn.net/suncongbo/article/details/77488127 URL: http://acm.hdu.edu.cn/showproblem.php?pid=2795题目大意:有一个h*w的木板 (h, w<=1e9), 现在有n (n<=2e5)张1*xi的海报要贴在木板上,按1~n的顺序每次贴海报时会选择最上的一排的最左边贴 (海报不能互相覆盖), 求每张海报会被贴在哪一行

HDU 1542 Atlantis 线段树+离散化+扫描线

题意:给出一些矩形的最上角坐标和右下角坐标,求这些矩形的面积并. NotOnlySuccess 线段树专辑中扫描线模板题,弱智的我对着大大的代码看了一下午才搞懂. 具体见思路见注释=.= #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define lson rt<<1,l,mid #define rson rt<<1|1,mid

HDU 1828 Picture 线段树+扫描线

题意:给你一些矩形的左上角点的坐标和右下角点的坐标,求周长并 最显而易见的思路就是对于x轴和y轴做两次扫描线,对于负数的坐标进行离散化.每次增加的值是线段变化量的绝对值.具体写法和求面积并的差不多. #include <cstdio> #include <algorithm> #include <cstring> #include <vector> using namespace std; #define lson rt << 1 , l , m

HDU 1542 Atlantis(线段树扫描线)

http://acm.hdu.edu.cn/showproblem.php?pid=1542 Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6788    Accepted Submission(s): 2970 Problem Description There are several ancient Greek

POJ 1177/HDU 1828 picture 线段树+离散化+扫描线 轮廓周长计算

求n个图矩形放下来,有的重合有些重合一部分有些没重合,求最后总的不规则图型的轮廓长度. 我的做法是对x进行一遍扫描线,再对y做一遍同样的扫描线,相加即可.因为最后的轮廓必定是由不重合的线段长度组成的,这样理论上是对的 要注意处理高度相同的线段,把底边优先处理(在代码里就是f标记为1的线段),因为若是一个矩形的底边和另一个矩形的上边重合,则这个轮廓肯定不能算 不过POJ和HDU的数据好像都比较弱,我没进行上面的细节处理也AC了,不过一个很简单的数据就会不对,所以还是要处理一下才是真正正确的代码 我

hdu 1542 Atlantis(线段树&amp;扫描线&amp;面积并)

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6386    Accepted Submission(s): 2814 Problem Description There are several ancient Greek texts that contain descriptions of the fabled i

hdu 1828 Picture(线段树&amp;扫描线&amp;周长并)

Picture Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2578    Accepted Submission(s): 1363 Problem Description A number of rectangular posters, photographs and other pictures of the same shap

hdu 1542 Atlantis(线段树)

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6899    Accepted Submission(s): 3022 Problem Description There are several ancient Greek texts that contain descriptions of the fabled i

hdu 4864(2) 线段树

对task和machine的yi由小到大进行排序,然后对machine来跟task配对.当machine[].yi >= task[].yi时,就更新线段树,在1-1440上做线段树,线段树存的是task[].xi,同时用用优先队列保存task[].yi:当machine[].yi < task[].yi时,就查找 1到machine[].xi最大的值.如果存在最大值的话,把优先队列里的task[].yi取出来..这样一个machine就匹配到了一个最优的任务.还是看代码好好意会吧,细节挺多的