HDU5638 / BestCoder Round #74 (div.1) 1003 Toposort 线段树+拓扑排序

Toposort

问题描述

给出nn个点mm条边的有向无环图. 要求删掉恰好kk条边使得字典序最小的拓扑序列尽可能小.

输入描述

输入包含多组数据. 第一行有一个整数TT, 表示测试数据组数. 对于每组数据:

第一行包含3个整数nn, mm和kk (1 \le n \le 100000, 0 \le k \le m \le 200000)(1≤n≤100000,0≤k≤m≤200000), 表示图中结点数目, 图中边的数目以及要删的边数.

接下来mm行, 每行包含两个整数u_iu?i?? and v_iv?i??, 表示存在一条u_iu?i??到v_iv?i??的有向边 (1 \le u_i, v_i \le n)(1≤u?i??,v?i??≤n).

输入保证给定的图是一个DAG. 输入数据中nn的和不超过10^610?6??. 输入数据中mm的和不超过2 \cdot 10^62⋅10?6??.

输出描述

对于每组数据, 输出一个整数S = (\displaystyle\sum_{i=1}^{n}{i\cdot p_i}) \text{ mod } (10^9 + 7)S=(?i=1?∑?n??i⋅p?i??) mod (10?9??+7), 其中p_{1}, p_{2}, ..., p_{n}p?1??,p?2??,...,p?n??是字典序最小的那个拓扑序列.

输入样例

3
4 2 0
1 2
1 3
4 5 1
2 1
3 1
4 1
2 3
2 4
4 4 2
1 2
2 3
3 4
1 4

输出样例

30
27
30

 题解:

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

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

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

///1085422276

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include<vector>
using namespace std;
using namespace std ;
typedef long long ll;
#define mem(a) memset(a,0,sizeof(a))
#define pb push_back
const int  N=100000+50;
const int  mod = 1e9+7;
const int  inf = 1e9+7;

int ind[N],head[N],t,n,m,K,vis[N];
vector<int > ans;
vector<int >G[N];
struct ss {
   int l,r,sum,index;
}tr[N*5];
struct sss {
  int to,next;
}e[N*20];
void init() {
  t=1;mem(head);mem(ind);ans.clear();mem(vis);
  for(int i=0;i<N;i++)G[i].clear();
}
void add(int u,int v) {e[t].to=v;e[t].next=head[u];head[u]=t++;}
void build(int k,int s,int t) {
     tr[k].l=s;tr[k].r=t;
     if(s==t) {
        tr[k].sum=ind[s];
        tr[k].index=s;
        return ;
     }
     int  mid=(s+t)>>1;
     build(k<<1,s,mid);
     build(k<<1|1,mid+1,t);
     tr[k].sum=min(tr[k<<1].sum,tr[k<<1|1].sum);
}
int ask(int k,int s,int t,int c) {
    int ret;
    if(tr[k].l==tr[k].r&&tr[k].l==s) {
            return tr[k].index;
    }
    int mid=(tr[k].l+tr[k].r)>>1;
    if(tr[k<<1].sum<=c) {
       ret=ask(k<<1,s,mid,c);
    }
    else  {
         ret=ask(k<<1|1,mid+1,t,c);
    }
    return ret;
}
void update(int k,int x,int c) {
     if(tr[k].l==tr[k].r&&tr[k].l==x) {
        tr[k].sum+=c;
        return ;
     }
     int mid=(tr[k].l+tr[k].r)>>1;
     if(x<=mid) update(k<<1,x,c);
     else update(k<<1|1,x,c);
     tr[k].sum=min(tr[k<<1].sum,tr[k<<1|1].sum);
}
int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d%d",&n,&m,&K);
        init();int u,v,check;
        for( int i=1;i<=m;i++) {
            scanf("%d%d",&u,&v);
            ind[v]++;
            G[u].pb(v);
        }
        build(1,1,n);
        for(int i=1;i<=n;i++) {
            check=ask(1,1,n,K);
            ans.pb(check);
            K-=ind[check];
            update(1,check,inf);
            for(int j=0;j<G[check].size();j++) {
                update(1,G[check][j],-1);
                ind[G[check][j]]--;
            }
        }
        ll A = 0;
        for(int i=0;i<ans.size();i++) {
            A=(A+1ll*(i+1)*ans[i])%mod;
        }
        printf("%I64d\n",A);
    }
  return 0;
}
时间: 2024-10-14 05:11:31

HDU5638 / BestCoder Round #74 (div.1) 1003 Toposort 线段树+拓扑排序的相关文章

DP BestCoder Round #50 (div.2) 1003 The mook jong

题目传送门 1 /* 2 DP:这题赤裸裸的dp,dp[i][1/0]表示第i块板放木桩和不放木桩的方案数.状态转移方程: 3 dp[i][1] = dp[i-3][1] + dp[i-3][0] + 1; dp[i][0] = dp[i-1][1] + dp[i-1][0]; 4 比赛时二维dp写搓了,主要是边界情况的判断出错,比如dp[3][1] = 1,因为第3块放了木桩,其他地方不能再放,dp[3][0]同理 5 解释一下dp[i][1]的三种情况,可能是前面相隔2个放的方案或者是不放的

Codeforces Round #401 (Div. 2) E 贪心,线段树

Codeforces Round #401 (Div. 2) A 循环节 B 暴力排一下 C 标记出来,但10^5,特耿直地码了个O(n^2)的上去,最气的是在最后3分钟的时候被叉== D 从后往前贪心暴糙一下就好.比赛时一眼瞄出来了不敢写,搞不懂这样竟然不会超时.. E. Hanoi Factory 题意:n个环体,内径a[i],外径b[i],高h[i].当 a[i+1]<b[i]<=b[i+1] 时,第 i 个环体可以堆在第 i+1个环体上.求可以堆出的最高高度. tags:佩服那些大佬,

Codeforces Round #292 (Div. 2) D. Drazil and Tiles [拓扑排序 dfs]

传送门 D. Drazil and Tiles time limit per test 2 seconds memory limit per test 256 megabytes Drazil created a following problem about putting 1 × 2 tiles into an n × m grid: "There is a grid with some cells that are empty and some cells that are occupie

Codeforces Round #603 (Div. 2) E. Editor 线段树

E. Editor The development of a text editor is a hard problem. You need to implement an extra module for brackets coloring in text. Your editor consists of a line with infinite length and cursor, which points to the current character. Please note that

ACM学习历程—HDU5587 Array(数学 &amp;&amp; 二分 &amp;&amp; 记忆化 || 数位DP)(BestCoder Round #64 (div.2) 1003)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5587 题目大意就是初始有一个1,然后每次操作都是先在序列后面添加一个0,然后把原序列添加到0后面,然后从0到末尾,每一个都加上1. 例如:a0, a1, a2 => a0, a1, a2, 1, a0+1, a1+1, a2+1 题解中是这么说的:“ 其实Ai为i二进制中1的个数.每次变化A{k+2^i}=A{k}+1,(k<2^?i??)不产生进位,二进制1的个数加1.然后数位dp统计前m个数二

哈密顿图 BestCoder Round #53 (div.2) 1003 Rikka with Graph II

题目传送门 题意:判断是否为哈密顿图 分析:首先一种情况是不合法的:也就是度数为1的点超过2个:合法的有:,那么从度数为1的点开始深搜,如果存在一种走法能够走完n个点那么存在哈密顿路 收获:学习资料 代码: /************************************************ * Author :Running_Time * Created Time :2015-8-29 20:37:34 * File Name :C.cpp *******************

Codeforces Round #290 (Div. 2) C. Fox And Names 拓扑排序

C. Fox And Names time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Fox Ciel is going to publish a paper on FOCS (Foxes Operated Computer Systems, pronounce: "Fox"). She heard a rumor: t

Codeforces Round #292 (Div. 1) B. Drazil and Tiles(拓扑排序)

题目地址:codeforces 292 B 用队列维护度数为1的点,也就是可以唯一确定的点,然后每次找v1,v2,并用v2来更新与之相连的点,如果更新后的点度数为1,就加入队列.若最后还有为"."的,说明无解或解不唯一. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #i

Codeforces Round #541 (Div. 2) D 并查集 + 拓扑排序

https://codeforces.com/contest/1131/problem/D 题意 给你一个n*m二维偏序表,代表x[i]和y[j]的大小关系,根据表构造大小分别为n,m的x[],y[],使得两个数组中最大的数尽量小 题解 按照偏序表,构造出从小到大的拓扑图 如何解决相等的数的偏序关系? 用并查集缩点后再进行拓扑排序 如何解决最大的数最小? 只需要使得同一层的数相同就行,可以一批处理栈中的元素,对于一批栈中的元素产生的新点,先放进一个容器里,然后等到这批栈清空了,再把这个容器中的点