杭电多校<五> set & 树的深度 & 树上建边

 

 这题开始纠结了很久,到底该怎么维护每个窗口排队的人数,考虑了优先队列和数组,后来知道了要用set

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N= 2e5 + 5;
struct Data { int arrival, spent; }data[N];
struct Timeline {
	ll time; int type, id;
	Timeline(ll _time = 0, int _type = 0, int _id = 0) :
		time(_time), type(_type), id(_id) {}
	// type = 0 for departure, type = 1 for arrival
	bool operator < (const Timeline &t) const {
		if(time != t.time) return time > t.time;
		return type > t.type;
	}
};
priority_queue<Timeline> Tl;
struct Queue {
	int num, id;
	Queue(int _num = 0, int _id = 0) :
		num(_num), id(_id) {}
	bool operator < (const Queue &t) const {
		if(num == t.num) return id < t.id;
		return num < t.num;
	}
}q[N];
set<Queue> Que;
int T, n, m, Queue_select[N];
ll ans, Last[N];
int main() {
	// freopen("test.in", "r", stdin);
	// freopen("test.out", "w", stdout);
	scanf("%d", &T);
	while(T--) {
		scanf("%d%d", &n, &m);
		for(int i = 1; i <= n; ++i)
			scanf("%d%d", &data[i].arrival, &data[i].spent);
		for(int i = 1; i <= n; ++i)
			Tl.push(Timeline(data[i].arrival, 1, i));
		Que.clear();
		for(int i = 1; i <= m; ++i) {
			q[i].num = 0, q[i].id = i;
			Que.insert(q[i]);
			Last[i] = 0;
		}
		while(!Tl.empty()) {
			auto tl = Tl.top(); Tl.pop();
			ll time = tl.time; int type = tl.type, id = tl.id;
			if(type == 0) {
				int qid = Queue_select[id];
				Que.erase(Queue(q[qid].num, q[qid].id));
				Que.insert(Queue(--q[qid].num, q[qid].id));
			}
			else {
				auto que = *Que.begin();
				int num = que.num, qid = que.id;
				Que.erase(que);
				Queue_select[id] = qid;
				if(num == 0) Last[qid] = time + data[id].spent;
				else Last[qid] += data[id].spent;
				q[qid].num++; que.num++;
				Que.insert(que);
				Tl.push(Timeline(Last[qid], 0, id));
			}
		}
		ans = 0;
		for(int i = 1; i <= m; ++i) ans = max(ans, Last[i]);
		printf("%lld\n", ans);
	}
	
	return 0;
}

 

  

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
using std::max, std::priority_queue, std::pair;
using ll = long long;

const int maxn = 1e6 + 5;
int e[maxn << 3][3], head[maxn << 2], tot = -1;
int dep[maxn << 2], maxdep = 0, n = 0, k = 0, p = 0, s = 0, t = 0;

void addEdge(int u, int v, int w) {
    e[++tot][0] = v;
    e[tot][1] = head[u];
    e[tot][2] = w;
    head[u] = tot;
}

void dfs(int u, int fa) {
    dep[u] = dep[fa] + 1;
    maxdep = max(maxdep, dep[u]);
    for (int i = head[u]; ~i; i = e[i][1]) {
        if (e[i][0] == fa)
            continue;
        dfs(e[i][0], u);
    }
}

ll dis[maxn << 2];
bool vis[maxn << 2];
void dijkstra() {
    memset(dis, 0x3f, sizeof(dis));
    memset(vis, false, sizeof(vis));
    dis[s] = 0;
    priority_queue<pair<ll, int>> pq;
    pq.emplace(0, s);
    while (!pq.empty()) {
        int u = pq.top().second;
        pq.pop();
        if (vis[u])
            continue;
        vis[u] = true;
        for (int i = head[u]; ~i; i = e[i][1]) {
            int v = e[i][0], w = e[i][2];
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                pq.emplace(-dis[v], v);
            }
        }
    }
}

void solve() {
    memset(head, -1, sizeof(head));
    tot = -1, maxdep = 0;
    scanf("%d", &n);
    int u = 0, v = 0, w = 0;
    for (int i = 1; i <= n - 1; ++i) {
        scanf("%d %d %d", &u, &v, &w);
        addEdge(u, v, w), addEdge(v, u, w);
    }
    dep[0] = -1;
    dfs(1, 0);
    scanf("%d %d", &k, &p);
    for (int i = 1; i <= n; ++i) {
        if (dep[i] != 0)
            addEdge(n + 2 * dep[i] - 1, i, p);
        if (dep[i] != maxdep)
            addEdge(n + 2 * (dep[i] + 1), i, p);
        if (dep[i] + k <= maxdep)
            addEdge(i, n + 2 * (dep[i] + k) - 1, 0);
        if (dep[i] - k >= 0)
            addEdge(i, n + 2 * (dep[i] - k + 1), 0);
    }
    scanf("%d %d", &s, &t);
    dijkstra();
    printf("%lld\n", dis[t]);
}

int main() {
    int T = 0;
    scanf("%d", &T);
    for (int cas = 1; cas <= T; ++cas)
        solve();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值