题目链接:hdoj 5638 Toposort
题意:给定
n
个点和
思路:记录入度,建在线段树上。下面就是查询
AC 代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#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;
}