首页 > 其他分享 >20240710

20240710

时间:2024-07-18 21:56:58浏览次数:12  
标签:20240710 return int void long tga tgv

T2

CF1303G Sum of Prefix Sums

考虑这个东西的本质其实是 \(\sum (n - i + 1)a_i\)。又对于路径计数问题,我们考虑能否快速合并两个区间的答案,发现这是非常可以的,需要记录的信息也很少。于是考虑点分治,然后对每个重心建李超树查询即可。由于路径有方向,需要正反查两遍。

代码
#include <iostream>
using namespace std;
const int inf = 2147483647;
int n;
long long a[150005];
int head[150005], nxt[300005], to[300005], ecnt;
void add(int u, int v) { to[++ecnt] = v, nxt[ecnt] = head[u], head[u] = ecnt; }
bool ban[150005];
int deg[150005];
struct node {
    int fr;
    long long down, up, sum;
    int len;
} lf[150005];
int lcnt;
struct Line {
    long long k, b;
    long long operator()(int x) { return k * x + b; }
} T[600005];
struct Segment_Tree {
    void Clear(int o, int l, int r) {
        T[o] = (Line) { 0, 0 };
        if (l == r) 
            return;
        int mid = (l + r) >> 1;
        Clear(o << 1, l, mid);
        Clear(o << 1 | 1, mid + 1, r);
    }
    void Insert(int o, int l, int r, Line v) {
        if (!T[o].k) {
            T[o] = v;
            return;
        }
        int mid = (l + r) >> 1;
        if (T[o](mid) < v(mid)) 
            swap(T[o], v);
        if (l == r) 
            return;
        long long l1 = T[o](l), l2 = v(l), r1 = T[o](r), r2 = v(r);
        if (l1 < l2) 
            Insert(o << 1, l, mid, v);
        if (r1 < r2) 
            Insert(o << 1 | 1, mid + 1, r, v);
    }
    long long Query(int o, int l, int r, int x) {
        if (l == r) 
            return T[o](x);
        int mid = (l + r) >> 1;
        if (x <= mid) 
            return max(Query(o << 1, l, mid, x), T[o](x));
        else 
            return max(Query(o << 1 | 1, mid + 1, r, x), T[o](x));
    }
} seg;
int sz[150005], msz[150005];
int Root, Rsz = inf;
void getroot(int x, int fa, int S) {
    sz[x] = 1;
    msz[x] = 0;
    for (int i = head[x]; i; i = nxt[i]) {
        int v = to[i];
        if (v != fa && !ban[v]) {
            getroot(v, x, S);
            sz[x] += sz[v];
            msz[x] = max(msz[x], sz[v]);
        }
    }
    msz[x] = max(msz[x], S - sz[x]);
    if (msz[x] < Rsz) 
        Rsz = msz[x], Root = x;
}
// down & len dont count root
// up & sum count root
int dep[150005], mxd;
void dfs(int x, int fa, long long down, long long up, long long sum, int fr) {
    sz[x] = 1;
    mxd = max(mxd, dep[x] = dep[fa] + 1);
    if (deg[x] == 1) 
        lf[++lcnt] = ((node) { fr, down, up, sum, dep[x] });
    for (int i = head[x]; i; i = nxt[i]) {
        int v = to[i];
        if (v != fa && !ban[v]) {
            dfs(v, x, down + sum + a[v] - a[Root], up + a[v] * (dep[x] + 2), sum + a[v], fr);
            sz[x] += sz[v];
        }
    }
}
long long ans = 0;
void Solve(int x) {
    ban[x] = 1;
    lcnt = 0;
    dep[x] = 0;
    mxd = 0;
    sz[x] = 1;
    for (int i = head[x]; i; i = nxt[i]) {
        int v = to[i];
        if (!ban[v]) {
            dfs(v, x, a[v], a[v] * 2 + a[x], a[x] + a[v], v);
            sz[x] += sz[v];
        }
    }
    seg.Clear(1, 0, mxd);
    lf[lcnt + 1].fr = lf[0].fr = -1;
    for (int i = 1; i <= lcnt;) {
        ans = max(ans, lf[i].down + a[x] * (lf[i].len + 1));
        int j = i;
        while (lf[j].fr == lf[i].fr) ans = max(ans, seg.Query(1, 0, mxd, lf[j].len) + lf[j].down), ++j;
        while (i < j) seg.Insert(1, 0, mxd, (Line) { lf[i].sum, lf[i].up }), ++i;
    }
    seg.Clear(1, 0, mxd);
    for (int i = lcnt; i;) {
        int j = i;
        while (lf[j].fr == lf[i].fr) ans = max(ans, seg.Query(1, 0, mxd, lf[j].len) + lf[j].down), --j;
        while (i > j) seg.Insert(1, 0, mxd, (Line) { lf[i].sum, lf[i].up }), --i;
    }
    ans = max(ans, seg.Query(1, 0, mxd, 0));
    for (int i = head[x]; i; i = nxt[i]) {
        int v = to[i];
        if (!ban[v]) {
            Rsz = inf;
            getroot(v, 0, sz[v]);
            Solve(Root);
        }
    }
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for (int i = 1; i < n; i++) {
        int u, v;
        cin >> u >> v;
        add(u, v);
        add(v, u);
        ++deg[u], ++deg[v];
    }
    for (int i = 1; i <= n; i++) cin >> a[i];
    Rsz = inf;
    getroot(1, 0, n);
    Solve(Root);
    cout << ans << "\n";
    return 0;
}

T6

CF706F T-shirts

考虑把所有人拥有的钱放在一起考虑。对于每一件衣服,所有当前拥有的钱大于等于当前价格的人会进行购买,之后这些人的钱数减去当前价格,同时答案加一。考虑使用平衡树维护这个东西。若当前价格为 \(p\),会发现钱数在 \([p, 2p]\) 之间的人钱数减去 \(p\) 之后落在 \([0, p]\),而这和原本钱数在 \([0, p]\) 的人产生冲突,会导致平衡树无法正常合并(合并要求一棵树的最大值小于等于另一颗的最小值)。因此对于这部分,直接暴力插入即可。容易发现每个人每次被暴力插入会使得其钱数减少至少二分之一,因此每个人被暴力插入的次数在 \(\log\) 级别,总复杂度可以保证。

代码
#include <iostream>
#include <algorithm>
#include <random>
using namespace std;
random_device rd;
mt19937 mtrand(rd());
int n, q;
struct Shirt {
    int c, q;
} a[200005];
struct node {
    int l, r, v, id, sz, ans;
    int tgv, tga;
    unsigned pr;
} T[200005];
int ncnt;
int New(int v, int id) {
    T[++ncnt] = (node) { 0, 0, v, id, 1, 0, 0, 0, mtrand() };
    return ncnt;
}
void pushdown(int x) {
    T[T[x].l].v += T[x].tgv;
    T[T[x].l].tgv += T[x].tgv;
    T[T[x].r].v += T[x].tgv;
    T[T[x].r].tgv += T[x].tgv;
    T[T[x].l].ans += T[x].tga;
    T[T[x].l].tga += T[x].tga;
    T[T[x].r].ans += T[x].tga;
    T[T[x].r].tga += T[x].tga;
    T[x].tga = T[x].tgv = 0;
}
void pushup(int x) { T[x].sz = T[T[x].l].sz + 1 + T[T[x].r].sz; }
void Split(int x, int& l, int& r, int v) {
    if (!x) 
        return l = r = 0, void();
    pushdown(x);
    if (T[x].v <= v) 
        Split(T[x].r, T[l = x].r, r, v);
    else 
        Split(T[x].l, l, T[r = x].l, v);
    pushup(x);
}
int Merge(int x, int y) {
    if (!x || !y) 
        return x | y;
    pushdown(x), pushdown(y);
    if (T[x].v > T[y].v) 
        swap(x, y);
    if (T[x].pr < T[y].pr) {
        T[x].r = Merge(T[x].r, y);
        pushup(x);
        return x;
    } else {
        T[y].l = Merge(x, T[y].l);
        pushup(y);
        return y;
    }
}
int rt;
int to;
void dfs(int x, int v) {
    pushdown(x);
    if (T[x].l) 
        dfs(T[x].l, v);
    if (T[x].r) 
        dfs(T[x].r, v);
    T[x].l = T[x].r = 0;
    pushup(x);
    int a, b;
    T[x].v -= v, T[x].ans++;
    Split(to, a, b, T[x].v);
    to = Merge(a, Merge(x, b));
}
int ans[1000005];
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i].c >> a[i].q;
    sort(a + 1, a + n + 1, [](Shirt a, Shirt b) { return (a.q == b.q) ? (a.c < b.c) : (a.q > b.q); });
    cin >> q;
    for (int i = 1; i <= q; i++) {
        int x, y, v;
        cin >> v;
        Split(rt, x, y, v);
        rt = Merge(x, Merge(New(v, i), y));
    }
    for (int i = 1; i <= n; i++) {
        int x, y, z, w;
        Split(rt, x, w, a[i].c - 1);
        Split(w, y, z, a[i].c << 1);
        to = x;
        dfs(y, a[i].c);
        T[z].v -= a[i].c, T[z].tgv -= a[i].c;
        T[z].ans++, T[z].tga++;
        rt = Merge(to, z);
    }
    for (int i = 1; i <= q; i++) cout << ans[i] << " ";
    cout << "\n";
    return 0;
}

标签:20240710,return,int,void,long,tga,tgv
From: https://www.cnblogs.com/forgotmyhandle/p/18301996

相关文章

  • Spark Exam 20240710黄洛天
    SparkExam20240710黄洛天0.整体总结时间安排:0-1h,+200pts,1h-4h,+0pts(expected+25pts)A,B较简单。C,D较难。排名4。Acceptable,完全不失误可以拿rnk1,所以还是挺好。D是大数据结构,不太想打(事实上做二维前缀和可以简单地拿到10pts)A.花菖蒲考虑构造完全二叉树,然后多余的1度......
  • 20240710概率期望
    概率基础知识不写了,反正应该知道的都知道但是有几个跟容斥有关的不知道,我要记录下1.互斥事件可加性:对于n个互斥的事件\(P(A_1\cup...\cupA_n)=\sum_{i=1}^{n}A_i\)2.独立事件可乘性:对于n个对立的事件\(P(A_1\cap...\capA_n)=\prod_{i=1}^{n}A_i\)3.n重伯努利实验:一次实验......