https://ac.nowcoder.com/acm/contest/57360/H
连通图,边比点多一,那就是有两个环,每个时刻要做的就是删掉两条边消掉这两个环。两种情况,要么是不共边的两个环,要么是共边的两个环。
要做的就是计算不同横坐标下一堆直线的最大值。可以用李超树,也可以用单调栈。
注意精度。
#include
using namespace std;
typedef long long ll;
const ll MAXN = 100005;
struct Edge {
ll a, b;
ll v_at(ll x) {return a*x + b;}
};
vector<pair<ll, ll>> graph[MAXN];
vector<Edge> edges;
ll dep[MAXN], e_used[MAXN];
pair<ll, ll> fa[MAXN]; //
vector<pair<pair<ll, ll>, ll>> back_edges; // <, eid>, dep[u] > dep[v]
vector<vector<ll>> to_del_eids;
ll ans[MAXN];
vector<ll> tmpans[MAXN];
void dfs(ll x, ll Fa) {
dep[x] = dep[fa[x].first] + 1;
for (auto [o, eid]: graph[x]) if (!e_used[eid]) {
e_used[eid] = 1;
if (dep[o] == 0) {fa[o] = {x, eid}; dfs(o, x);}
else back_edges.push_back({{x, o}, eid});
}
}
void calc_to_del_eids() {
vector<ll> s(edges.size());
bool flag_intersect = false;
for (ll i=0; i<2; i++) {
auto [u, v] = back_edges[i].first;
s[back_edges[i].second] += (i+1);
for (ll x=u; x!=v; x=fa[x].first) {
s[fa[x].second] += (i+1);
flag_intersect |= (s[fa[x].second] == 3);
}
}
to_del_eids.resize(flag_intersect+2);
for (ll i=0; i<s.size(); i++) if (s[i])
to_del_eids[s[i]-1].push_back(i);
}
struct Frac {
__int128 u, v;
Frac(): u(0), v(1) {}
Frac(ll uu): u(uu), v(1) {}
Frac(ll uu, ll vv): u(uu), v(vv) {
ll g=__gcd(u<0 ? -u : u, v<0 ? v : -v);
if (g>1) u/=g, v/=g;
if (v < 0) u=-u, v=-v;
}
bool operator<(const Frac& x) {return u*x.v < v*x.u;}
bool operator<=(const Frac& x) {return u*x.v <= v*x.u;}
};
bool cmp(Edge &x, Edge &y) {return x.a!=y.a ? x.a < y.a : x.b > y.b;}
void fun(const vector<ll> &eids, ll T) {
vector<Edge> es;
vector<pair<Frac, Edge>> Q; //
for (ll i: eids) es.push_back(edges[i]);
sort(es.begin(), es.end(), cmp);
for (auto e: es) {
while (!Q.empty()) {
auto [st, te] = Q.back();
if (te.a == e.a) break; // te.b >= te.a
Frac t_intersect(e.b - te.b, te.a - e.a);
if (t_intersect <= st) {
Q.pop_back();
}
else {
Q.push_back({t_intersect, e});
break;
}
}
if (Q.empty()) Q.push_back({0, e});
}
Q.push_back({T+10, Edge{-1,-1}});
ll cur = 0;
for (ll i=0; i<=T; i++) {
while (Q[cur+1].first <= i) cur++;
tmpans[i].push_back(Q[cur].second.v_at(i));
}
}
void solve()
{
ll n, T;
ll sb=0, sa=0;
cin >>n >>T;
for (ll i=0, u, v, a, b; i<=n; i++) {
cin >>u >>v >>a >>b;
edges.push_back({a,b});
graph[u].push_back({v, edges.size()-1});
graph[v].push_back({u, edges.size()-1});
sa+=a;
sb+=b;
}
dfs(1, 0);
calc_to_del_eids();
ans[0] = sb;
for (ll i=1; i<=T; i++) ans[i] = ans[i-1] + sa;
for (const auto &eids: to_del_eids) fun(eids, T);
for (ll i=0; i<=T; i++) {
sort(tmpans[i].rbegin(), tmpans[i].rend());
cout <<(ans[i]-tmpans[i][0]-tmpans[i][1]) <<'\n';
}
}
int main()
{
solve();
return 0;
}