2026-01-29~02-03 hetao1733837 的刷题记录

2026-01-29~30 hetao1733837 的刷题记录

01-29

LGP5563 [Celeste-B] No More Running

原题链接:[Celeste-B] No More Running

分析

她好像有npy了......

我去学浦东了......
她好像原谅我了

理解为一个点,选一条以他为路径端点的树上路径权值模 mod ⁡ \operatorname{mod} mod 的最大值。怎么分治呢?哦,这也是点对!所以分治......
她好像还单着。

但是,这个取模太阴了......思考一下......
她为啥不回我消息?

我在干什么?我什么要在中午在机房看 B 站?

看这个会不会有什么启发?

思考一下......我么们考虑 merge......找到子树重心......然后......理论上我只能选一边啊......还是看题解吧......我们预处理模意义下树上两点路径距离,发现合并时最多进行一次取模,分讨是否取模即可。没了......

下午......思考一下什么时候可以写代码。那就到晚上了......彳亍......
她为什么还不回我?

其实再等一分钟就回我了......

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, mod, rt, mn, sum;
int sz[N], d[N], ans[N];
vector<pair<int, int>> e[N];
bool vis[N];
multiset<int> s;
void dfs1(int u, int fa){
    int mx = 0;
    sz[u] = 1;
    for (auto tmp : e[u]){
        int v = tmp.first;
        if (v == fa || vis[v]) 
            continue;
        dfs1(v, u);
        sz[u] += sz[v];
        mx = max(mx, sz[v]);
    }
    mx = max(mx, sum - sz[u]);
    if (mn > mx){
        mn = mx;
        rt = u;
    }
}
void dfs2(int u, int fa){
    s.insert(d[u]);
    for (auto tmp : e[u]){
        int v = tmp.first;
        if (v == fa || vis[v]) 
            continue;
        d[v] = (d[u] + tmp.second) % mod;
        dfs2(v, u);
    }
}
bool flag;
void modify(int u, int fa){
    if (flag)
        s.insert(d[u]);
    else
        s.erase(s.find(d[u]));
    for (auto tmp : e[u]){
        int v = tmp.first;
        if (v == fa || vis[v]) 
            continue;
        modify(v, u);
    }
}
void got(int u, int fa){
    auto it = s.upper_bound(mod - d[u] - 1);
    if (it != s.begin()){
        ans[u] = max(ans[u], d[u] + *(--it));
    }
    ans[u] = max(ans[u], (d[u] + *s.rbegin()) % mod);
    for (auto tmp : e[u]){
        int v = tmp.first;
        if (v == fa || vis[v]) 
            continue;
        got(v, u);
    }
}
void solve(int u){
    mn = 0x7f7f7f7f;
    dfs1(u, 0);
    dfs1(rt, 0);
    d[rt] = 0;
    dfs2(rt, 0);
    for (auto tmp : e[rt]){
        int v = tmp.first;
        if (vis[v]) 
            continue;
        flag = false;
        modify(v, rt);
        got(v, rt);
        flag = true;
        modify(v, rt);
    }
    ans[rt] = max(ans[rt], *s.rbegin());
    flag = false;
    modify(rt, 0);
    vis[rt] = true;
    for (auto tmp : e[rt]){
        int v = tmp.first;
        if (vis[v]) 
            continue;
        sum = sz[v];
        solve(v);
    }
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> mod;
    for (int i = 1, u, v, w; i < n; i++){
        cin >> u >> v >> w;
        e[u].push_back({v, w});
        e[v].push_back({u, w});
    }
    sum = n;
    solve(1);
    for (int i = 1; i <= n; i++)
        cout << ans[i] << '\n';
}

01-30

CF2126G2 Big Wins! (hard version)

原题链接:CF2126G2 Big Wins! (hard version)

分析

思考一下......这个东西的 tag 这么猎奇?二分查找数据结构分治启发式双指针......

样例太水了......根本盯不出来性质......看起来......那也不对啊......思索一下......

我似乎知道某个求中位数的 Trick ,不幸的是,已经想不起来了......太 ** 压抑了......

最小值很好确定, S T ST ST 表就可以......卡在中位数了......

第一步很典,固定最小值,向右逐步扩展,则呈双指针状物。

然后,拿一个单调栈确定包含此最小值的最大的区间。

哦,然后就是一个很典的东西了,将大于等于的记为1,小于的记为-1,看和就可以了

那么,问题转化为类似求前缀最大值、后缀最大值、区间和的杂糅,故可使用线段树。

似乎写完了......我不知道......看看代码,自己试着写一写吧......
古生物真有意思......

老外不会用结构体?

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int n, a[N];
struct node{
    int mx, pre, suf, sum;
};
node tr[N << 2];
struct segtree{
    void pushup(int p){
        tr[p].mx = max(tr[p << 1].mx, tr[p << 1 | 1].mx);
        tr[p].pre = max(tr[p << 1].pre, tr[p << 1].sum + tr[p << 1 | 1].pre);
        tr[p].suf = max(tr[p << 1 | 1].suf, tr[p << 1].suf + tr[p << 1 | 1].sum);
        tr[p].mx = max({tr[p].mx, tr[p].pre, tr[p].suf});
        tr[p].sum = tr[p << 1].sum + tr[p << 1 | 1].sum;
    }
    void build(int p, int l, int r){
        if (l == r){
            tr[p].mx = tr[p].pre = tr[p].suf = tr[p].sum = 0;
            return ;
        }
        int mid = (l + r) >> 1;
        build(p << 1, l, mid);
        build(p << 1 | 1, mid + 1, r);
        pushup(p);
    }
    node merge(node x, node y){
        int mx = max(x.mx, y.mx);
        int pre = max(x.pre, x.sum + y.pre);
        int suf = max(y.suf, x.suf + y.sum);
        mx = max({mx, pre, suf});
        int sum = x.sum + y.sum;
        return {mx, pre, suf, sum};
    }
    void modify(int p, int l, int r, int s, int val){
        if (l == r){
            tr[p].mx = max(val, 0);
            tr[p].pre = max(val, 0);
            tr[p].suf = max(val, 0);
            tr[p].sum = val;
            return ;
        }
        int mid = (l + r) >> 1;
        if (s <= mid)
            modify(p << 1, l, mid, s, val);
        else
            modify(p << 1 | 1, mid + 1, r, s, val);
        pushup(p);
    }
    node query(int p, int l, int r, int s, int t){
        if (l > r || s > t){
            return {0, 0, 0, 0};
        }
        if (l == s && r == t){
            return tr[p];
        }
        int mid = (l + r) >> 1;
        if (t <= mid)
            return query(p << 1, l, mid, s, t);
        else if (s > mid)
            return query(p << 1 | 1, mid + 1, r, s, t);
        else
            return merge(query(p << 1, l, mid, s, mid), 
                        query(p << 1 | 1, mid + 1, r, mid + 1, t));
    }
}T;
int solve(int n, vector<int> arr){
    int m = 0;
    for (int i = 1; i <= n; i++){
        a[i] = arr[i - 1];
        m = max(m, a[i]);
    }
    vector<int> ind[m + 1];
    for (int i = 1; i <= n; i++){
        ind[a[i]].push_back(i);
    }
    stack<int> s;
    s.push(0);
    a[0] = 0xc0c0c0c0;
    int l[n + 1];
    for (int i = 1; i <= n; i++){
        while (a[s.top()] >= a[i]){
            s.pop();
        }
        l[i] = s.top() + 1;
        s.push(i);
    }
    a[n + 1] = 0xc0c0c0c0;
    while (!s.empty()) 
    	s.pop();
    s.push(n + 1);
    int r[n + 1];
    for (int i = n; i >= 1; i--){
        while (a[s.top()] >= a[i]){
            s.pop();
        }
        r[i] = s.top() - 1;
        s.push(i);
    }
    int med = 1;
    T.build(1, 1, n);
    for (int i = 1; i <= n; i++){
        T.modify(1, 1, n, i, 1);
    }
    for (auto u : ind[1]){
        T.modify(1, 1, n, u, -1);
    }
    int ans = 0;
    for (int mn = 1; mn <= m; mn++){
        for (auto u : ind[mn]){
            int L = l[u], R = r[u];
            while (med < m){
                int left_val = (L <= u - 1) ? T.query(1, 1, n, L, u - 1).suf : 0;
                int right_val = (u + 1 <= R) ? T.query(1, 1, n, u + 1, R).pre : 0;
                int current = (a[u] < med ? -1 : 1);
                if (left_val + right_val + current >= 0){
                    med++;
                    for (auto v : ind[med]){
                        T.modify(1, 1, n, v, -1);
                    }
                } 
                else{
                    break;
                }
            }
        }
        ans = max(ans, med - mn);
    }
    return ans;
}
int t;
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> t;
    while (t--){
        cin >> n;
        vector<int> inp;
        for (int i = 1, x; i <= n; i++){
            cin >> x;
            inp.push_back(x);
        }
        cout << solve(n, inp) << '\n';
    }
    return 0;
}

02-01

LGP6329 【模板】点分树 / 震波

原题链接:【模板】点分树 / 震波

分析

动态开点真的需要开这么多空间吗?

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, m, v[N], rt;
vector<int> e[N];
int f[N][21], de[N], sz[N], mx[N];
bool vis[N];
void dfs(int u, int pa){
    f[u][0] = pa;
    de[u] = de[pa] + 1;
    for (auto v : e[u]){
        if (v == pa) 
            continue;
        dfs(v, u);
    }
}
int lca(int x, int y){
    if (de[x] < de[y]) 
        swap(x, y);
    int k = de[x] - de[y];
    for (int i = 0; i <= 20; i++){
        if (k & (1 << i)) 
            x = f[x][i];
    }
    if (x == y) 
        return y;
    for (int i = 20; i >= 0; i--){
        if (f[x][i] != f[y][i]){
            x = f[x][i];
            y = f[y][i];
        }
    }
    return f[x][0];
}
int getdis(int x, int y){
    return de[x] + de[y] - 2 * de[lca(x, y)];
}
void getrt(int u, int pa, int cnt){
    sz[u] = 1;
    mx[u] = 0;
    for (auto v : e[u]){
        if (v == pa || vis[v]) 
            continue;
        getrt(v, u, cnt);
        sz[u] += sz[v];
        mx[u] = max(mx[u], sz[v]);
    }
    mx[u] = max(mx[u], cnt - sz[u]);
    if (mx[u] < mx[rt]) 
        rt = u;
}
int dfn[N];
void solve(int u, int cnt){
    vis[u] = true;
    for (auto v : e[u]){
        if (vis[v]) 
            continue;
        rt = 0;
        int tmp = (sz[v] < sz[u]) ? sz[v] : (cnt - sz[u]);
        getrt(v, u, tmp);
        dfn[rt] = u;
        solve(rt, tmp);
    }
}
struct segtree{
    int root[N], ncnt = 0;
    struct node{
        int ls, rs, val;
    }tr[N * 50];
    void pushup(int p){
        tr[p].val = tr[tr[p].ls].val + tr[tr[p].rs].val;
    }
    void modify(int &p, int l, int r, int s, int val){
        if (!p) 
            p = ++ncnt;
        if (l == r){
            tr[p].val += val;
            return ;
        }
        int mid = (l + r) >> 1;
        if (s <= mid) 
            modify(tr[p].ls, l, mid, s, val);
        else 
            modify(tr[p].rs, mid + 1, r, s, val);
        pushup(p);
    }
    int query(int p, int l, int r, int s, int t){
        if(!p) 
            return 0;
        if (s <= l && r <= t) 
            return tr[p].val;
        int mid = (l + r) >> 1;
        int res = 0;
        if (s <= mid) 
            res += query(tr[p].ls, l, mid, s, t);
        if (t > mid) 
            res += query(tr[p].rs, mid + 1, r, s, t);
        return res;
    }
}T1, T2;
void change(int p, int val){
    int pos = p;
    while (pos){
        T1.modify(T1.root[pos], 0, n - 1, getdis(pos, p), val);
        if (dfn[pos]){
            T2.modify(T2.root[pos], 0, n - 1, getdis(dfn[pos], p), val);
        }
        pos = dfn[pos];
    }
}
int ask(int p, int k){
    int pos = p, lst = 0, res = 0;
    while (pos){
        if (getdis(pos, p) > k){
            lst = pos;
            pos = dfn[pos];
            continue;
        }
        res += T1.query(T1.root[pos], 0, n - 1, 0, k - getdis(pos, p));
        if (lst) 
            res -= T2.query(T2.root[lst], 0, n - 1, 0, k - getdis(pos, p));
        lst = pos;
        pos = dfn[pos];
    }
    return res;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; i++) 
        cin >> v[i];
    for (int i = 1, u, v; i < n; i++){
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs(1, 0);
    for (int j = 1; j <= 20; j++){
        for (int i = 1; i <= n; i++){
            f[i][j] = f[f[i][j - 1]][j - 1];
        }
    }
    mx[0] = 0x3f3f3f3f;
    rt = 0;
    getrt(1, 0, n);
    solve(rt, n);
    for (int i = 1; i <= n; i++){
        change(i, v[i]);
    }
    int lst = 0;
    for (int cs = 1, op, x, k, y; cs <= m; cs++){
        cin >> op >> x;
        if (op == 0){
            cin >> k;
            x ^= lst;
            k ^= lst;
            lst = ask(x, k);
            cout << lst << '\n';
        }
        else{
            cin >> y;
            x ^= lst;
            y ^= lst;
            change(x, y - v[x]);
            v[x] = y;
        }
    }
}

02-03

LGP3345 [ZJOI2015] 幻想乡战略游戏

原题链接:[ZJOI2015] 幻想乡战略游戏

分析

闪现了一个换根 DP 状物......为啥我看到了虚树......感觉这个和 lca 关系似乎很大啊......居然有树剖做法......但是,似乎点分树更好想......因为......思索一下......但是,我还是觉得......哦......难道是离线吗?但我还是想看看虚树做法......哦......原来是带权重心吗?那就是点分树了!然后......就是......上一个板子里就有一个向下跳的过程,但是会失去信息,所以,我看的题解直接做了一个预处理......没了......

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100005;
int n, Q;
vector<pair<int, int>> e[N];
map<int, int> d[N];
vector<int> tr[N];
int mx[N], sz[N], tot, rt;
bool vis[N];
void getrt(int u, int pa){
    sz[u] = 1;
    mx[u] = 0;
    for (auto tmp : e[u]){
        int v = tmp.first;
        if (v == pa || vis[v]) 
            continue;
        getrt(v, u);
        sz[u] += sz[v];
        mx[u] = max(mx[u], sz[v]);
    }
    mx[u] = max(mx[u], tot - sz[u]);
    if (mx[rt] > mx[u]) 
        rt = u;
}
void init(int u, int pa, int ro){
    sz[u] = 1;
    for (auto tmp : e[u]){
        int v = tmp.first, w = tmp.second;
        if (v == pa || vis[v]) 
            continue;
        d[ro][v] = d[ro][u] + w;
        init(v, u, ro);
        sz[u] += sz[v];
    }
}
int dfa[N], fa[N];
void dfs(int u){
    vis[u] = 1;
    d[u][u] = 0;
    init(u, 0, u);
    for (auto tmp : e[u]){
        int v = tmp.first;
        if (vis[v]) 
            continue;
        tot = sz[v];
        rt = 0;
        getrt(v, u);
        tr[u].push_back(rt);
        fa[rt] = u;
        dfa[rt] = v;
        dfs(rt);
    }
}
int sum[N], sum1[N], sum2[N];
void moidfy(int p, int val){
    int pos = p;
    while (pos){
        sum[pos] += val;
        sum1[pos] += d[pos][p] * val;
        if (fa[pos]) 
            sum2[pos] += d[fa[pos]][p] * val;
        pos = fa[pos];
    }
}
int got(int p){
    int res = sum1[p];
    int pos = p;
    while (fa[pos]){
        res += sum1[fa[pos]] - sum2[pos] + d[fa[pos]][p] * (sum[fa[pos]] - sum[pos]); 
        pos = fa[pos];
    }
    return res;
}
int query(int u){
    int res = got(u);
    for (auto v : tr[u]){
        int tmp = got(dfa[v]);
        if (tmp < res) 
            return query(v);
    }
    return res;
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> Q;
    for (int i = 1, a, b, c; i < n; i++){
        cin >> a >> b >> c;
        e[a].push_back({b, c});
        e[b].push_back({a, c});
    }
    mx[0] = 0x3f3f3f3f;
    tot = n;
    getrt(1, 0);
    int cur = rt;
    dfs(rt);
    for (int cs = 1, U, E; cs <= Q; cs++){
        cin >> U >> E;
        moidfy(U, E);
        cout << query(cur) << '\n';
    }
}
相关推荐
咩咩不吃草1 小时前
决策树三大核心算法详解:ID3、C4.5与CART
算法·决策树·机器学习
执行部之龙1 小时前
TCP八股完结篇
网络·笔记·网络协议·tcp/ip
晚风吹长发1 小时前
初步了解Linux中的POSIX信号量及环形队列的CP模型
linux·运维·服务器·数据结构·c++·算法
EnglishJun1 小时前
数据结构的学习(五)---树和二叉树
数据结构·学习·算法
日光倾2 小时前
【Vue.js 入门笔记】 状态管理器Vuex
vue.js·笔记·flutter
方安乐2 小时前
react笔记之tanstack
前端·笔记·react.js
新新学长搞科研2 小时前
【CCF主办 | 高认可度会议】第六届人工智能、大数据与算法国际学术会议(CAIBDA 2026)
大数据·开发语言·网络·人工智能·算法·r语言·中国计算机学会
近津薪荼2 小时前
优选算法——前缀和(1):一维前缀和
c++·学习·算法
多恩Stone2 小时前
【3D-AICG 系列-2】Trellis 2 的O-voxel (上) Shape: Flexible Dual Grid
人工智能·python·算法·3d·aigc