P2680 [NOIP2015 提高组] 运输计划

题意为让最长的路径最短,所以要 二分答案

考虑如何写 judge 函数。

设当前验证的答案为 x ,若所有 >x 的运输计划都经过一条边,且时间最长的运输计划 - 这条边的时间 <= x,则可行,反之则反。

#include <bits/stdc++.h>
#define d(x) cerr << #x << " => " << x << endl
#define dd(x) cerr << #x << endl
#define D cerr << "Passed [" << __FUNCTION__ << "] on line " << __LINE__ << endl
#define ms(x) memset(x, 0, sizeof x)
using namespace std;
int rd() {
    int f = 1, val = 0; char ch = getchar();
    while(!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
    while(isdigit(ch)) val = val * 10 + ch - '0', ch = getchar();
    return f * val;
}

void file() {
    freopen("in.in", "r", stdin);
    //freopen("out.out", "w+", stdout);
}

const int N = 3e5 + 5, M = 3e5 + 5;

struct Edge {
    int to, nxt, wei;
} Edge[M << 1];

struct trans {
    int u, v, dis, lca;
    bool operator<(const trans& a) const {
        return dis < a.dis;
    }
} trans[N << 1];

int head[N], belongTo[N], cnt, n, m;

void addEdge(int u, int v, int w) {
    Edge[++cnt].to = v;
    Edge[cnt].nxt = head[u];
    Edge[cnt].wei = w;
    head[u] = cnt;
}

int f[N][21], dep[N], dis[N];

void dfs1(int u, int fa, int depth, int d) {
    f[u][0] = fa; dep[u] = depth + 1; dis[u] = d;
    for(int i = 1; i <= 20; i++) f[u][i] = f[f[u][i - 1]][i - 1];
    for(int i = head[u]; i; i = Edge[i].nxt) {
        const int &v = Edge[i].to;
        if(v == fa) continue;
        belongTo[v] = Edge[i].wei;
        dfs1(v, u, depth + 1, d + Edge[i].wei);
    }
}

int lca(int x, int y) {
    if(dep[x] < dep[y]) swap(x, y);
    int dis = dep[x] - dep[y];
    for(int i = 20; ~i; i--) if(dis & (1 << i)) x = f[x][i];
    if(x == y) return x;
    for(int i = 20; ~i; i--) if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
    return f[x][0];
}

int d[N], a[N];

void dfs2(int u, int fa) {
    a[u] = d[u];
    for(int i = head[u]; i; i = Edge[i].nxt) {
        const int v = Edge[i].to;
        if(v == fa) continue;
        dfs2(v, u);
        a[u] += a[v];
    }
}

int judge(int x) {
    d(x);
    if(trans[m].dis <= x) return true;
    std::fill(d, d + N, 0);
    int lst = m;
    for(int j = m; j && trans[j].dis > x; j--) {
        lst = j;
        d[trans[j].u]++; d[trans[j].v]++; d[trans[j].lca] -= 2;
    }
    d(lst);
    std::fill(a, a + N, 0);
    dfs2(1, 0);
    int mx = 0;
    for(int i = 2; i <= n; i++) {
        if(m - lst + 1 == a[i]) mx = max(belongTo[i], mx);
    }

    if(trans[m].dis - mx <= x) return true;
    return false;
}

signed main() {
#ifdef LOCAL
    file();
#endif
    n = rd(), m = rd();
    for(int i = 1; i < n; i++)  {
        int u = rd(), v = rd(), w = rd();
        addEdge(u, v, w); addEdge(v, u, w);
    }

    int l = 0, r = 0x3f3f3f3f, ans = 0;

    dfs1(1, 0, 1, 0);

    for(int i = 1; i <= m; i++) {
        int u = rd(), v = rd();
        int lcav = lca(u, v);
        trans[i].u = u;
        trans[i].v = v;
        trans[i].dis = dis[u] + dis[v] - 2 * dis[lcav];
        trans[i].lca = lcav;
    }

    sort(trans + 1, trans + m + 1);

    while(l <= r) {
        int mid = (l + r) >> 1;
        if(judge(mid)) r = mid - 1, ans = mid;
        else l = mid + 1;
    }

    cout << ans << endl;

    return 0;
}

P7273 ix35 的等差数列

由于值域较小,可以考虑枚举公差。

构造数列 1, 1+d, 1+2d, ... 1+(n-1)d 与原数列作差,n - 众数出现次数即为答案。注意不能逾越值域。

注意可能这种循环的写法可能爆 long long。

#include <bits/stdc++.h>
#define d(x) cerr << #x << " => " << x << endl
#define dd(x) cerr << #x << endl
#define D cerr << "Passed [" << __FUNCTION__ << "] on line " << __LINE__ << endl
#define ms(x) memset(x, 0, sizeof x)
#define int long long
using namespace std;
int rd() {
    int f = 1, val = 0; char ch = getchar();
    while(!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
    while(isdigit(ch)) val = val * 10 + ch - '0', ch = getchar();
    return f * val;
}

void file() {
    freopen("in.in", "r", stdin);
    //freopen("out.out", "w+", stdout);
}

int n, w;
const int N = 3e5 + 6;
int a[N], b[N];
unordered_map<int, int> maps;

int judge(int d) {
    b[1] = 1;
    maps.clear();
    for(int i = 2; i <= n; i++) b[i] = b[i - 1] + d;
    for(int i = 1; i <= n; i++) maps[a[i] - b[i]]++;
    int res = 0;
    for(unordered_map<int, int>::iterator it = maps.begin(); it != maps.end(); it++) {
        if(it -> first + b[1] < 1) continue;
        if(it -> first + b[n] > w) continue;
        res = max(res, it -> second);
    }
    return n - res;
}

signed main() {
#ifdef LOCAL
    file();
#endif
    n = rd(), w = rd();
    for(int i = 1; i <= n; i++) a[i] = rd();
    if(n == 1) return puts("0"), 0;
    int ans = 0x3f3f3f3f;
    for(int d = 0; d <= w; d++) {
        if(1 + (n - 1) * d <= w) {
            ans = min(ans, judge(d));
        }
    }
    printf("%lld\n", ans);
    return 0;
}

CF372C Watching Fireworks is Fun

单调队列优化 dp。

#include <bits/stdc++.h>
#define d(x) cerr << #x << " => " << x << endl
#define dd(x) cerr << #x << endl
#define D cerr << "Passed [" << __FUNCTION__ << "] on line " << __LINE__ << endl
#define ms(x) memset(x, 0, sizeof x)
#define int long long
using namespace std;
int rd() {
    int f = 1, val = 0; char ch = getchar();
    while(!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
    while(isdigit(ch)) val = val * 10 + ch - '0', ch = getchar();
    return f * val;
}

void file() {
    freopen("in.in", "r", stdin);
    //freopen("out.out", "w+", stdout);
}

const int N = 1.5e5 + 5, M = 305;

struct Firework {
    int a, b, t;
    Firework() : a(0), b(0), t(0) { }
} fw[N];

int f[2][N];
deque<int> Q;

int myabs(int x) {
    return x < 0 ? -x : x;
}

signed main() {
#ifdef LOCAL
    file();
#endif
    int n = rd(), m = rd(), d = rd();
    for(int i = 1; i <= m; i++) {
        fw[i].a = rd();
        fw[i].b = rd();
        fw[i].t = rd();
    }

    for(int i = 1; i <= m; ++i) {
        Q.clear();
        int ed = min(1 + (fw[i].t - fw[i - 1].t) * d, n);
        for(int j = 1; j <= ed; j++) {
            while(!Q.empty() && f[0][Q.back()] <= f[0][j]) Q.pop_back(); 
            Q.push_back(j);
        }

        for(int j = 1; j <= n; j++) {
            while(!Q.empty() && Q.front() < j - (fw[i].t - fw[i - 1].t) * d) Q.pop_front();
            while (ed < min(j + (fw[i].t - fw[i - 1].t) * d, n)) {
                ++ed;
                while(!Q.empty() && f[0][Q.back()] <= f[0][ed]) Q.pop_back();
                Q.push_back(ed);
            }
            f[1][j] = fw[i].b - myabs(fw[i].a - j) + f[0][Q.front()];
        }

        for(int j = 1; j <= n; j++) {
            f[0][j] = f[1][j];
        }

        std::fill(f[1] + 1, f[1] + n + 1, 0);
    }

    cout << *max_element(f[0] + 1, f[0] + n + 1) << endl;
    return 0;
}

CF75C Modified GCD

一句话,两个数的公约数一定是他们最大公约数的约数。

另外 gcd(a, b) = gcd(b, a % b) 。。。

留一张图,约数质因子数量级表.jpg

图片上传锅了,等有时间搭个图床。

[PlaceHolder]

#include <bits/stdc++.h>
#define d(x) cerr << #x << " => " << x << endl
#define dd(x) cerr << #x << endl
#define D cerr << "Passed [" << __FUNCTION__ << "] on line " << __LINE__ << endl
#define ms(x) memset(x, 0, sizeof x)
using namespace std;
int rd() {
    int f = 1, val = 0; char ch = getchar();
    while(!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
    while(isdigit(ch)) val = val * 10 + ch - '0', ch = getchar();
    return f * val;
}

void file() {
    freopen("in.in", "r", stdin);
    //freopen("out.out", "w+", stdout);
}

int gcd(int a, int b) {
    return !b ? a : gcd(b, a % b);
}

vector<int> fac;

signed main() {
#ifdef LOCAL
    file();
#endif
    int x = rd(), y = rd();
    int gcdv = gcd(x, y);
    for(int i = 1; i * i <= gcdv; i++) {
        if(gcdv % i == 0) {
            fac.push_back(i);
            if(gcdv / i != i) fac.push_back(gcdv / i);
        }
    }

    sort(fac.begin(), fac.end());

    int m = rd();
    for(int i = 1; i <= m; i++) {
        int a = rd(), b = rd();
        auto p = upper_bound(fac.begin(), fac.end(), b);
        if(p == fac.begin()) {
            puts("-1");
            continue;
        }

        --p;
        if(a <= *p) {
            printf("%d\n", *(p));
        } else {
            puts("-1");
        }
    }

    return 0;
}

P3609 [USACO17JAN]Hoof, Paper, Scissor G

比较激进的思路是不保留当前状态的出法(剪刀石头布),但这样会造成复杂度的退化 O(n^2m)

状态还是多保留一些信息好。。

#include <bits/stdc++.h>
#define d(x) cerr << #x << " => " << x << endl
#define dd(x) cerr << #x << endl
#define D cerr << "Passed [" << __FUNCTION__ << "] on line " << __LINE__ << endl
#define ms(x) memset(x, 0, sizeof x)
using namespace std;
int rd() {
    int f = 1, val = 0; char ch = getchar();
    while(!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
    while(isdigit(ch)) val = val * 10 + ch - '0', ch = getchar();
    return f * val;
}

void file() {
    freopen("in.in", "r", stdin);
    //freopen("out.out", "w+", stdout);
}

const int N = 1e5 + 5, M = 22;

#define Hoof 0
#define Scissors 1
#define Paper 2

const int table[3][3] = {
    {0, 1, 0},
    {0, 0, 1}, 
    {1, 0, 0}
};

int f[N][M][3], g[N];

int judge(int a, int b) {
    return table[a][b];
}

signed main() {
#ifdef LOCAL
    file();
#endif
    int n = rd(), k = rd();
    for(int i = 1; i <= n; i++) {
        char ch[5];
        scanf("%s", ch + 1);
        if(ch[1] == 'P') g[i] = Paper;
        if(ch[1] == 'S') g[i] = Scissors;
        if(ch[1] == 'H') g[i] = Hoof;
    }

//  for(int i = 1; i <= n; i++) cout << g[i] << endl;

    for(int i = 1; i <= n; i++) {
        for(int j = 0; j <= k; j++) {
            for(int u = 0; u < 3; u++) {
                for(int b = 0; b < 3; b++) {
                    if(u == b) f[i][j][u] = max(f[i][j][u], f[i - 1][j][b] + judge(u, g[i]));
                    else if(j > 0) f[i][j][u] = max(f[i][j][u], f[i - 1][j - 1][b] + judge(u, g[i]));
                }
            }
        }
    }

    int ans = 0;
    for(int j = 0; j <= k; j++) {
        for(int u = 0; u < 3; ++u) {
            ans = max(ans, f[n][j][u]);
        }
    }

    cout << ans << endl;
    return 0;
}

P3567 [POI2014]KUR-Couriers

可持久化数据结构系列。

主席树板子题。查询第 (r - l + 1) / 2 + 1 大和该数出现次数即可。

#include <bits/stdc++.h>
#define d(x) cerr << #x << " => " << x << endl
#define dd(x) cerr << #x << endl
#define D cerr << "Passed [" << __FUNCTION__ << "] on line " << __LINE__ << endl
#define ms(x) memset(x, 0, sizeof x)
using namespace std;
int rd() {
    int f = 1, val = 0; char ch = getchar();
    while(!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
    while(isdigit(ch)) val = val * 10 + ch - '0', ch = getchar();
    return f * val;
}

void file() {
    freopen("in.in", "r", stdin);
    //freopen("out.out", "w+", stdout);
}

class SegmentTree {
#define MID int mid = (l + r) >> 1
#define lson l, mid, node[x].ls
#define rson mid + 1, r, node[x].rs
public :
    static const int N = 5e5 + 5;
    struct Node {
        int ls, rs, sum;
    } node[N * 40];

    int root[N], cnt;

    SegmentTree() : cnt(0) { }

    int build(int l, int r) {
        int x = ++cnt;
        if(l == r) {
            node[x].ls = node[x].rs = node[x].sum = 0;
            return x;
        }
        MID; 
        node[x].ls = build(l, mid);
        node[x].rs = build(mid + 1, r);
        push_up(x);
        return x;
    }

    int clone(int x) {
        node[++cnt] = node[x];
        return cnt;
    }

    void push_up(int x) {
        node[x].sum = node[node[x].ls].sum + node[node[x].rs].sum;
    }

    void modify_add(int l, int r, int &x, int p, int v) {
        x = clone(x);
        if(l == r) {
            node[x].sum += v;
            return ;
        }
        MID;
        if(p <= mid) modify_add(lson, p, v);
        if(p > mid) modify_add(rson, p, v);
        push_up(x);
    }

    int query(int a, int b, int n) {
        int k = (b - a) / 2 + 1, ok = k;
        int l = 1, r = n;
        a = root[a], b = root[b];
        while(l < r) {
            MID;
            int lsv = node[node[b].ls].sum - node[node[a].ls].sum;
            if(lsv >= k) {
                r = mid;
                a = node[a].ls;
                b = node[b].ls;
            } else {
                l = mid + 1;
                k -= lsv;
                a = node[a].rs;
                b = node[b].rs;
            }
        }
        return node[b].sum - node[a].sum >= ok ? l : 0;
    }

} st;

signed main() {
#ifdef LOCAL
    file();
#endif
    int n = rd(), m = rd();
    st.root[0] = st.build(1, n);
    for(int i = 1; i <= n; i++) {
        int v = rd();
        st.root[i] = st.root[i - 1];
        st.modify_add(1, n, st.root[i], v, 1);
    }

//  for(int i = 1; i <= n; i++) {
//      cout << st.root[i] << " ";
//  }
//  cout << endl;

    for(int i = 1; i <= m; ++i) {
        int l = rd(), r = rd();
        int res = st.query(l - 1, r, n);
        printf("%d\n", res);
    }
    return 0;
}

CF1474A - Puzzle From the Future

#include <bits/stdc++.h>
#define d(x) cerr << #x << " => " << x << endl
#define dd(x) cerr << #x << endl
#define D cerr << "Passed [" << __FUNCTION__ "] on line " << __LINE__ << endl
using namespace std;
int rd() {
    int f = 1, val = 0; char ch = getchar();
    while(!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
    while(isdigit(ch)) val = val * 10 + ch - '0', ch = getchar();
    return f * val;
}

void file() {
    freopen("in.in", "r", stdin);
    //freopen("out.out", "w+", stdout);
}

void solve() {
    int n; cin >> n;
    string a, b; cin >> b; a = b;
//  cout << b << endl;
    int bef = 0;
    for(int i = 0; i < (int) b.size(); i++) {
        if(b[i] == '1') {
            if(bef == 2) a[i] = '0', bef = 1;
            else if(bef == 1) a[i] = '1', bef = 2;
            else if(bef == 0) a[i] = '1', bef = 2;
        } else if(b[i] == '0') {
            if(bef == 2) a[i] = '1', bef = 1;
            else if(bef == 1) a[i] = '0', bef = 0;
            else if(bef == 0) a[i] = '1', bef = 1;
        }
    }

    cout << a << '\n';
}

signed main() {
#ifdef LOCAL
    file();
#endif
    int T; cin >> T;
    while(T--) solve();
    return 0;
}

CF1474B - Different Divisors

#include <bits/stdc++.h>
#define d(x) cerr << #x << " => " << x << endl
#define dd(x) cerr << #x << endl
#define D cerr << "Passed [" << __FUNCTION__ "] on line " << __LINE__ << endl
using namespace std;
int rd() {
    int f = 1, val = 0; char ch = getchar();
    while(!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
    while(isdigit(ch)) val = val * 10 + ch - '0', ch = getchar();
    return f * val;
}

void file() {
    freopen("in.in", "r", stdin);
    //freopen("out.out", "w+", stdout);
}

const int N = 1e5 + 6;
int isnt[N];
vector<int> Primes;

void solve() {
    int d = rd();
    int t = *(lower_bound(Primes.begin(), Primes.end(), 1 + d));
    int x = *(lower_bound(Primes.begin(), Primes.end(), t + d));
    printf("%d\n", t * x);
}

void init(int n) {
    isnt[0] = isnt[1] = true;
    for(int i = 1; i <= n; i++) {
        if(!isnt[i]) {
            Primes.push_back(i);
            for(int j = 2; i * j <= n; j++) {
                isnt[i * j] = true;
            }
        }
    }
}

signed main() {
#ifdef LOCAL
    file();
#endif
    init(N - 4);
//  for(int i = 0; i < 25; i++) printf("%d\n", Primes[i]);
    int T = rd();
    while(T--) solve();
    return 0;
}

CF1474C - Array Destruction

总觉得我的做法复杂度不对。。

upd: 竟然是std???

#include <bits/stdc++.h>
#define d(x) cerr << #x << " => " << x << endl
#define dd(x) cerr << #x << endl
#define D cerr << "Passed [" << __FUNCTION__ << "] on line " << __LINE__ << endl
#pragma GCC optimize(2)
using namespace std;
int rd() {
    int f = 1, val = 0; char ch = getchar();
    while(!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
    while(isdigit(ch)) val = val * 10 + ch - '0', ch = getchar();
    return f * val;
}

void file() {
    freopen("in.in", "r", stdin);
    //freopen("out.out", "w+", stdout);
}

const int N = 1e5 + 5;
int a[N];
multiset<int> S, vS;

void debug() {
    for(auto it : S) cout << it << " ";
    cout << endl;
}

vector<pair<int, int> > opt;
int n;

int solve2(int);

void solve1() {
    vS.clear();
    n = rd() * 2;
    for(int i = 1; i <= n; i++) a[i] = rd();
    for(int i = 1; i <= n; i++) vS.insert(a[i]);

    sort(a + 1, a + n + 1);

    for(int i = 1; i < n; i++) {
        S.clear();
        S = vS;
        if(solve2(a[i])) return ;
    }
    puts("NO");
}

int solve2(int lucky) {
    opt.clear();
    int lstmax = *(--S.end());
    S.erase(--S.end());
    S.erase(S.find(lucky));

    opt.push_back(make_pair(lstmax, lucky));    

    while(S.size()) {
        auto umaxp = --S.end();
        int umax = *umaxp;
        multiset<int>::iterator it = S.find(lstmax - umax);
        if(it != S.end()) ;
        else return false;
        if(umaxp == it) return false;

        opt.push_back(make_pair(*it, umax));
        S.erase(S.find(lstmax - umax));
        S.erase(--S.end());
        lstmax = umax;
    }

    puts("YES");
    printf("%d\n", opt[0].first + opt[0].second);
    for(int i = 0; i < n / 2; i++) {
        printf("%d %d\n", opt[i].first, opt[i].second);
    }
    return true;
}

signed main() {
#ifdef LOCAL
    file();
#endif
    int T = rd();
    while(T--) solve1();
    return 0;
}

P1967 [NOIP2013 提高组] 货车运输

建立最大生成树。

#include <bits/stdc++.h>
#define d(x) cerr << #x << " => " << x << endl
#define dd(x) cerr << #x << endl
#define D cerr << "Passed [" << __FUNCTION__ << "] on line " << __LINE__ << endl
#define ms(x) memset(x, 0, sizeof x)
using namespace std;
int rd() {
    int f = 1, val = 0; char ch = getchar();
    while(!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
    while(isdigit(ch)) val = val * 10 + ch - '0', ch = getchar();
    return f * val;
}

void file() {
    freopen("in.in", "r", stdin);
    //freopen("out.out", "w+", stdout);
}

const int N = 1e4 + 5, M = 5e4 + 4;

struct Edge {
    int to, nxt, wei;
} Edge[M << 1];

int head[N], cnt;

void addEdge(int u, int v, int w) {
    Edge[++cnt].to = v;
    Edge[cnt].nxt = head[u];
    head[u] = cnt;
    Edge[cnt].wei = w;
}

class UnionSet {
public:
    static const int N = ::N;
    int fa[N];

    UnionSet() {
        for(int i = 1; i < N; i++) fa[i] = i;
    }

    int leader(int x) {
        return fa[x] == x ? x : fa[x] = leader(fa[x]);
    }

    void merge(int x, int y) {
        int fx = leader(x), fy = leader(y);
        if(fx == fy) return ;
        fa[fx] = fy;
    }
} us;

struct Prepares {
    int u, v, w;
    bool operator<(const Prepares& a) const {
        return w > a.w;
    }
} pre[M];

int dep[N], f[N][21], minx[N][21], belongTo[N], vis[N];

void dfs1(int u, int fa, int depth) {
    f[u][0] = fa; dep[u] = depth; vis[u] = 1;
    for(int i = 1; i <= 20; i++) f[u][i] = f[f[u][i - 1]][i - 1];
    for(int i = head[u]; i; i = Edge[i].nxt) {
        const int v = Edge[i].to;
        if(v == fa) continue;
//      cout << u << " " << v << " " << Edge[i].wei << endl;
        dfs1(v, u, depth + 1);
        belongTo[v] = Edge[i].wei;
    }
}

void dfs2(int u, int fa) {
    minx[u][0] = belongTo[u];
    for(int i = 1; i <= 20; i++) minx[u][i] = min(minx[u][i - 1], minx[f[u][i - 1]][i - 1]);
    for(int i = head[u]; i; i = Edge[i].nxt) {
        const int v = Edge[i].to;
        if(v == fa) continue;
        dfs2(v, u);
    }
}

typedef pair<int, int> pi;

pi lca(int x, int y) {
    int mx = 0x3f3f3f3f;
    if(dep[x] < dep[y]) swap(x, y);
    int dis = dep[x] - dep[y];
    for(int i = 20; ~i; i--) if(dis & (1 << i)) mx = min(minx[x][i], mx), x = f[x][i];
    if(x == y) return make_pair(x, mx);
    for(int i = 20; ~i; i--) if(f[x][i] != f[y][i]) mx = min(mx, min(minx[x][i], minx[y][i])), x = f[x][i], y = f[y][i];
    return make_pair(f[x][0], min(mx, min(minx[x][0], minx[y][0])));
}

signed main() {
#ifdef LOCAL
    file();
#endif
    memset(belongTo, 0x3f, sizeof belongTo);
    int n = rd(), m = rd();
    for(int i = 1; i <= m; i++) {
        pre[i].u = rd();
        pre[i].v = rd();
        pre[i].w = rd();
    }

    sort(pre + 1, pre + m + 1);

    for(int i = 1; i <= m; i++) {
        if(us.leader(pre[i].u) == us.leader(pre[i].v)) continue;
        us.merge(pre[i].u, pre[i].v);
        addEdge(pre[i].u, pre[i].v, pre[i].w);
        addEdge(pre[i].v, pre[i].u, pre[i].w);
    }

    for(int i = 1; i <= n; i++) if(!vis[i]) dfs1(i, 0, 1), dfs2(i, 0);
    int Q = rd();
    for(int i = 1; i <= Q; i++) {
        int x = rd(), y = rd();
        if(us.leader(x) != us.leader(y)) {
            puts("-1");
        } else {
            pi res = lca(x, y);
            printf("%d\n", res.second);
        }
    }

    return 0;
}

树剖题选

P3384 【模板】轻重链剖分

需要注意的是找 lca 时,应该跳所在链链顶深度更深的而不是该点深度更深的点。

#include <bits/stdc++.h>
#define d(x) cerr << #x << " => " << x << endl
#define dd(x) cerr << #x << endl
#define D cerr << "Passed [" << __FUNCTION__ << "] on line " << __LINE__ << endl
#define ms(x) memset(x, 0, sizeof x)
#define int long long
using namespace std;
int rd() {
    int f = 1, val = 0; char ch = getchar();
    while(!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
    while(isdigit(ch)) val = val * 10 + ch - '0', ch = getchar();
    return f * val;
}

void file() {
    freopen("in.in", "r", stdin);
    //freopen("out.out", "w+", stdout);
}

const int N = 1e5 + 5;
int n, m, r, mod, a[N];

class SegmentTree {
#define MID int mid = (l + r) >> 1
#define lson l, mid, x << 1
#define rson mid + 1, r, x << 1 | 1
public :
    static const int N = ::N;
    int val[N << 2], add[N << 2];

    SegmentTree() {
        ms(val); 
        ms(add);
    }

    void modify_add(int l, int r, int x, int p, int q, int v) {
        if(p <= l && r <= q) {
            add[x] = (add[x] + v) % mod;
            val[x] = (val[x] + (r - l + 1) * v % mod) % mod;
            return ;
        }
        MID; push_down(l, r, x);
        if(p <= mid) modify_add(lson, p, q, v);
        if(q > mid) modify_add(rson, p, q, v);
        push_up(x);
    }

    void push_up(int x) {
        val[x] = (val[x << 1] + val[x << 1 | 1]) % mod;
    }

    void push_down(int l, int r, int x) {
        if(!add[x]) return ;
        MID;
        val[x << 1] = (val[x << 1] + (mid - l + 1) * add[x] % mod) % mod;
        val[x << 1 | 1] = (val[x << 1 | 1] + (r - mid) * add[x] % mod) % mod;
        add[x << 1] = (add[x << 1] + add[x]) % mod;
        add[x << 1 | 1] = (add[x << 1 | 1] + add[x]) % mod;
        add[x] = 0;
    }

    int query(int l, int r, int x, int p, int q) {
        if(p <= l && r <= q) 
            return val[x];

        MID; push_down(l, r, x);
        int res = 0;
        if(p <= mid) res = (res + query(lson, p, q)) % mod;
        if(q > mid) res = (res + query(rson, p, q)) % mod;
        return res;
    }

} st;

struct Edge {
    int to, nxt;
} Edge[N << 1];

int head[N], cnt;

void addEdge(int u, int v) {
    Edge[++cnt].to = v;
    Edge[cnt].nxt = head[u];
    head[u] = cnt;
}

int dfn[N], dep[N], fa[N], sz[N], hs[N], top[N], idx;

void dfs1(int u, int d, int depth) {
    dep[u] = depth; fa[u] = d; sz[u] = 1;
    int maxs = 0;
    for(int i = head[u]; i; i = Edge[i].nxt) {
        const int v = Edge[i].to;
        if(v == d) continue;
        dfs1(v, u, depth + 1);
        sz[u] += sz[v];
        if(sz[v] > maxs) maxs = sz[v], hs[u] = v;
    }
}

void dfs2(int u, int tf) {
    top[u] = tf;
    dfn[u] = ++idx; 
    if(sz[u] == 1) return ;
    dfs2(hs[u], tf);
    for(int i = head[u]; i; i = Edge[i].nxt) {
        const int &v = Edge[i].to;
        if(v == fa[u] || v == hs[u]) continue;
        dfs2(v, v);
    }
}

int qRange(int x, int y) {
    int res = 0;
    while(top[x] != top[y]) {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        res = (res + st.query(1, n, 1, dfn[top[x]], dfn[x])) % mod; x = fa[top[x]];
    }
    if(dep[x] < dep[y]) swap(x, y);
    return (res + st.query(1, n, 1, dfn[y], dfn[x])) % mod;
}

void mRange(int x, int y, int z) {
    while(top[x] != top[y]) {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        st.modify_add(1, n, 1, dfn[top[x]], dfn[x], z); x = fa[top[x]];
    }
    if(dep[x] < dep[y]) swap(x, y);
    st.modify_add(1, n, 1, dfn[y], dfn[x], z);
}

signed main() {
#ifdef LOCAL
    file();
#endif
    n = rd(), m = rd(), r = rd(), mod = rd();
    for(int i = 1; i <= n; i++) {
        a[i] = rd();
    }

    for(int i = 1; i < n; i++) {
        int u = rd(), v = rd();
        addEdge(u, v); addEdge(v, u);
    }

    dfs1(r, r, 1);
    dfs2(r, r);

    for(int i = 1; i <= n; i++) {
        st.modify_add(1, n, 1, dfn[i], dfn[i], a[i]);
    }

    for(int i = 1; i <= m; i++) {
        int opt = rd();
        if(opt == 1) {
            int x = rd(), y = rd(), z = rd() % mod;
            mRange(x, y, z);
        } else if(opt == 2) {
            int x = rd(), y = rd();
            printf("%lld\n", qRange(x, y) % mod);
        } else if(opt == 3) {
            int x = rd(), z = rd() % mod;
            st.modify_add(1, n, 1, dfn[x], dfn[x] + sz[x] - 1, z);
        } else if(opt == 4) {
            int x = rd();
//          d(x); d(dfn[x]); d(dfn[x] + sz[x] - 1);
            printf("%lld\n", st.query(1, n, 1, dfn[x], dfn[x] + sz[x] - 1) % mod);
        }
    }

    return 0;
}

P3178 [HAOI2015]树上操作

记录一段有问题的代码。如果跳到深度为 2 的点为链顶,则最后一步不会将根的值计算在内。

int qRange(int x) {
    if(x == 1) return st.query(1, n, 1, id[1], id[1]);
    int res = 0;
    while(x != 1) {
        res += st.query(1, n, 1, id[top[x]], id[x]);
        x = fa[top[x]];
    }
    return res;
}
#include <bits/stdc++.h>
#define d(x) cerr << #x << " => " << x << endl
#define dd(x) cerr << #x << endl
#define D cerr << "Passed [" << __FUNCTION__ << "] on line " << __LINE__ << endl
#define ms(x) memset(x, 0, sizeof x)
#define int long long
using namespace std;
int rd() {
    int f = 1, val = 0; char ch = getchar();
    while(!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
    while(isdigit(ch)) val = val * 10 + ch - '0', ch = getchar();
    return f * val;
}

void file() {
    freopen("in.in", "r", stdin);
    //freopen("out.out", "w+", stdout);
}

const int N = 1e5 + 6;

class SegmentTree {
#define MID int mid = (l + r) >> 1
#define lson l, mid, x << 1
#define rson mid + 1, r, x << 1 | 1
public :
    static const int N = ::N;
    int sum[N << 2], add[N << 2];

    SegmentTree() {
        ms(sum); 
        ms(add);
    }

    void push_up(int x) {
        sum[x] = sum[x << 1] + sum[x << 1 | 1];
    }

    void push_down(int l, int r, int x) {
        if(!add[x]) return ;
        MID;
        add[x << 1] += add[x];
        add[x << 1 | 1] += add[x];
        sum[x << 1] += (mid - l + 1) * add[x];
        sum[x << 1 | 1] += (r - mid) * add[x];
        add[x] = 0;
    }

    void modify_add(int l, int r, int x, int p, int q, int v) {
        if(p <= l && r <= q) {
            add[x] += v;
            sum[x] += (r - l + 1) * v;
            return ;
        }
        MID; push_down(l, r, x);
        if(p <= mid) modify_add(lson, p, q, v);
        if(q > mid) modify_add(rson, p, q, v);
        push_up(x);
    }

    int query(int l, int r, int x, int p, int q) {
        if(p <= l && r <= q) return sum[x];
        MID; push_down(l, r, x);
        int res = 0;
        if(p <= mid) res += query(lson, p, q);
        if(q > mid) res += query(rson, p, q);
        return res;
    }
} st;

struct Edge {
    int to, nxt;
} Edge[N << 1];

int head[N], cnt, n, m;

void addEdge(int u, int v) {
    Edge[++cnt].to = v;
    Edge[cnt].nxt = head[u];
    head[u] = cnt;
}

int fa[N], dep[N], id[N], top[N], sz[N], hs[N], a[N], idx;

void dfs1(int u, int d, int depth) {
    dep[u] = depth; fa[u] = d; sz[u] = 1; int mx = 0;
    for(int i = head[u]; i; i = Edge[i].nxt) {
        const int v = Edge[i].to;
        if(v == d) continue;
        dfs1(v, u, depth + 1);
        sz[u] += sz[v];
        if(sz[v] > mx) hs[u] = v, mx = sz[v];
    }
}

void dfs2(int u, int tf) {
    id[u] = ++idx; top[u] = tf;
    if(sz[u] == 1) return ;
    dfs2(hs[u], tf); 
    for(int i = head[u]; i; i = Edge[i].nxt) {
        const int v = Edge[i].to;
        if(v == fa[u] || v == hs[u]) continue;
        dfs2(v, v);
    }
}

int qRange(int x) {
    int res = 0;
    while(top[x] != 1) {
        res += st.query(1, n, 1, id[top[x]], id[x]);
        x = fa[top[x]];
    }
    return res + st.query(1, n, 1, 1, id[x]);
}

signed main() {
#ifdef LOCAL
    file();
#endif
    n = rd(), m = rd();
    for(int i = 1; i <= n; i++) {
        a[i] = rd();
    }

    for(int i = 1; i < n; i++) {
        int u = rd(), v = rd();
        addEdge(u, v); addEdge(v, u);
    }

    dfs1(1, 1, 1);
    dfs2(1, 1);
    for(int i = 1; i <= n; i++) st.modify_add(1, n, 1, id[i], id[i], a[i]);
    for(int i = 1; i <= m; i++) {
        int opt = rd();
        if(opt == 1) {
            int x = rd(), v = rd();
            st.modify_add(1, n, 1, id[x], id[x], v);
        } else if(opt == 2) {
            int x = rd(), v = rd();
            st.modify_add(1, n, 1, id[x], id[x] + sz[x] - 1, v);
        } else if(opt == 3) {
            int x = rd();
            printf("%lld\n", qRange(x));
        }
    }
    return 0;
}

P2590 [ZJOI2008]树的统计

#include <bits/stdc++.h>
#define d(x) cerr << #x << " => " << x << endl
#define dd(x) cerr << #x << endl
#define D cerr << "Passed [" << __FUNCTION__ << "] on line " << __LINE__ << endl
#define ms(x) memset(x, 0, sizeof x)
#define int long long
using namespace std;
int rd() {
    int f = 1, val = 0; char ch = getchar();
    while(!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
    while(isdigit(ch)) val = val * 10 + ch - '0', ch = getchar();
    return f * val;
}

void file() {
    freopen("in.in", "r", stdin);
    //freopen("out.out", "w+", stdout);
}

const int N = 3e4 + 6;

class SegmentTree {
#define MID int mid = (l + r) >> 1
#define lson l, mid, x << 1
#define rson mid + 1, r, x << 1 | 1
public :
    static const int N = ::N;
    int sum[N << 2], add[N << 2], maxx[N << 2];

    SegmentTree() {
        ms(sum); 
        ms(add);
        ms(maxx);
    }

    void push_up(int x) {
        sum[x] = sum[x << 1] + sum[x << 1 | 1];
        maxx[x] = max(maxx[x << 1], maxx[x << 1 | 1]);
    }

    void modify(int l, int r, int x, int p, int v) {
        if(l == r) {
            sum[x] = maxx[x] = v;
            return ;
        }
        MID;
        if(p <= mid) modify(lson, p, v);
        if(p > mid) modify(rson, p, v);
        push_up(x);
    }

    int query_sum(int l, int r, int x, int p, int q) {
        if(p <= l && r <= q) return sum[x];
        MID; 
        int res = 0;
        if(p <= mid) res += query_sum(lson, p, q);
        if(q > mid) res += query_sum(rson, p, q);
        return res;
    }

    int query_max(int l, int r, int x, int p, int q) {
        if(p <= l && r <= q) return maxx[x];
        MID;
        int res = 0xafafafafafafafaf;
        if(p <= mid) res = max(res, query_max(lson, p, q));
        if(q > mid) res = max(res, query_max(rson, p, q));
        return res;
    }

} st;

struct Edge {
    int to, nxt;
} Edge[N << 1];

int head[N], cnt, n;

void addEdge(int u, int v) {
    Edge[++cnt].to = v;
    Edge[cnt].nxt = head[u];
    head[u] = cnt;
}

int fa[N], dep[N], id[N], top[N], sz[N], hs[N], a[N], idx;

void dfs1(int u, int d, int depth) {
    fa[u] = d; dep[u] = depth; sz[u] = 1; int mx = 0;
    for(int i = head[u]; i; i = Edge[i].nxt) {
        const int &v = Edge[i].to;
        if(v == d) continue;
        dfs1(v, u, depth + 1);
        sz[u] += sz[v];
        if(sz[v] > mx) mx = sz[v], hs[u] = v;
    }
}

void dfs2(int u, int tf) {
    id[u] = ++idx; top[u] = tf;
    if(sz[u] == 1) return ;
    dfs2(hs[u], tf);
    for(int i = head[u]; i; i = Edge[i].nxt) {
        const int &v = Edge[i].to;
        if(v == fa[u] || v == hs[u]) continue;
        dfs2(v, v);
    }
}

int mRange(int x, int y) {
    int res = 0xafafafafafafafaf;
    while(top[x] != top[y]) {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        res = max(res, st.query_max(1, n, 1, id[top[x]], id[x])); x = fa[top[x]];
    }
    if(dep[x] < dep[y]) swap(x, y);
    return max(res, st.query_max(1, n, 1, id[y], id[x]));
}

int sRange(int x, int y) {
    int res = 0;
    while(top[x] != top[y]) {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        res += st.query_sum(1, n, 1, id[top[x]], id[x]); x = fa[top[x]];
    }
    if(dep[x] < dep[y]) swap(x, y);
    return res + st.query_sum(1, n, 1, id[y], id[x]);
}

signed main() {
#ifdef LOCAL
    file();
#endif
    n = rd();
    for(int i = 1; i < n; i++) {
        int u = rd(), v = rd();
        addEdge(u, v); addEdge(v, u);
    }

    for(int i = 1; i <= n; i++) a[i] = rd();
    dfs1(1, 1, 1);
    dfs2(1, 1);
    for(int i = 1; i <= n; i++) st.modify(1, n, 1, id[i], a[i]);

    int m = rd();
    for(int i = 1; i <= m; i++) {
        char opt[10];
        scanf("%s", opt + 1);
        if(opt[4] == 'X') { //QMAX
            int u = rd(), v = rd();
            printf("%lld\n", mRange(u, v));
        } else if(opt[4] == 'N') { //CHANGE
            int x = rd(), a = rd();
            st.modify(1, n, 1, id[x], a);
        } else if(opt[4] == 'M') { //QSUM
            int u = rd(), v = rd();
            printf("%lld\n", sRange(u, v));
        }
    }

    return 0;
}
最后修改:2021 年 01 月 21 日
如果觉得我的文章对你有用,请随意赞赏