P3242 [HNOI2015]接水果

P3242 HNOI2015接水果
分块求区间第K小,然后用树上莫队(欧拉序分块,特判lca)做(这个做法可能会被卡,不过莫队被卡应该很正常吧?
令离散化后值域为 (C_{max})
利用分块可以把求第K小的复杂度降到 (O(sqrt{C_{max}})) 也就是 (O(sqrt{P}))
然后就是树上莫队基本操作。
顺便一提,分块求第K小可以去做 这道题

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>

using namespace std;

typedef long long ll;
const ll MAXN = 1e6+10;

ll N, P, Q, head[MAXN], SIZ, c[MAXN], cv[2000], cnt = -1, out[MAXN] ,in[MAXN], block[MAXN], num, fa[22][MAXN], dep[MAXN];
ll seq[MAXN], tot, vis[MAXN], VSIZ, vtot, vblock[MAXN], ans[MAXN], val[MAXN], st[2000], ed[2000], used[MAXN];
vector <ll> V[MAXN], q;

struct edg {ll nt, to;} E[MAXN];
struct ask {
    ll l, r, k, id;
    friend bool operator < (ask a, ask b) {return block[a.l] == block[b.l] ? block[a.r] < block[b.r] : (block[a.l] < block[b.l]);}
} A[MAXN];

void add(ll, ll);
void calc(ll);
void dfs(ll, ll);
ll gtn(ll);
ll lca(ll, ll);

int main() {
	//freopen("P3242.in", "r", stdin);
    memset(head, -1, sizeof(head));
    scanf("%lld%lld%lld", &N, &P, &Q);
    SIZ = (ll)pow(N, 2.0 / 3.0);
    VSIZ = (ll)pow(P, 2.0 / 3.0);
    for (ll x, y, i = 1; i < N; i++) {
        scanf("%lld%lld", &x, &y);
        add(x, y);
        add(y, x);
    }
    for (ll x, y, v, i = 1; i <= P; i++) {
        scanf("%lld%lld%lld", &x, &y, &v);
        V[x].push_back(i);
        V[y].push_back(i);
        q.push_back(v);
        val[i] = v;
    }
    sort(q.begin(), q.end());
    q.erase(unique(q.begin(), q.end()), q.end());
    for (ll i = 1; i <= P; i++) val[i] = lower_bound(q.begin(), q.end(), val[i]) - q.begin() + 1;
    dfs(1, 0);
    for (ll i = 1; i <= num; i++) {
        if (i % SIZ == 1) tot++;
        block[i] = tot;
    }
    for (ll i = 1; i <= P; i++) {
        if (i % VSIZ == 1) vtot++;
        vblock[i] = vtot;
        ed[vblock[i]] = i;
    }
    for (ll i = P; i; i--) st[vblock[i]] = i;
    for (ll x, y, i = 1; i <= Q; i++) {
        scanf("%lld%lld%lld", &x, &y, &A[i].k);
        if (in[x] > in[y]) swap(x, y);
		A[i].id = i;
		A[i].r = in[y];
		if (lca(x, y) == x) A[i].l = in[x];
		else A[i].l = out[x];
    }
    sort(A+1, A+Q+1);
    ll l = 1, r = 0;
    for (ll i = 1; i <= Q; i++) {
        while (l > A[i].l) calc(seq[--l]);
        while (r < A[i].r) calc(seq[++r]);
        while (l < A[i].l) calc(seq[l++]);
        while (r > A[i].r) calc(seq[r--]);
        ll x = seq[A[i].l], y = seq[A[i].r]; ll tem = lca(x, y);
        ll flag = ((tem == x) | (tem == y));
        if (!flag) calc(tem);
        ans[A[i].id] = gtn(A[i].k);
        if (!flag) calc(tem);
    }
    for (ll i = 1; i <= Q; i++) printf("%lld
", ans[i]);
    return 0;
}

ll gtn(ll kth) {
    ll tmp = 0, lv, rv;
    for (ll i = 1; i <= vtot; i++) {
        tmp += cv[i];
        if (tmp >= kth) {tmp -= cv[i], lv = st[i], rv = ed[i]; break;}
    }
    for (ll i = lv; i <= rv; i++) {
        tmp += c[i];
        if (tmp >= kth) return q.at(i-1);
    }
    return -1;
}

void calc(ll pos) {
    if (!used[pos]) { // 1
        for (unsigned int i = 0; i < V[pos].size(); i++) {
            ll tem = V[pos][i]; vis[tem]++;
            if (vis[tem] == 2) c[val[tem]]++, cv[vblock[val[tem]]]++;
        }
    } else { // -1
        for (unsigned int i = 0; i < V[pos].size(); i++) {
            ll tem = V[pos][i]; vis[tem]--;
            if (vis[tem] == 1) c[val[tem]]--, cv[vblock[val[tem]]]--;
        }
    }
    used[pos] ^= 1;
}

void dfs(ll n, ll ff) {
    in[n] = ++num, fa[0][n] = ff, seq[num] = n;
    for (ll i = 1; i <= 20; i++) fa[i][n] = fa[i-1][fa[i-1][n]];
    for (ll i = head[n]; ~i; i = E[i].nt) {
        ll v = E[i].to;
        if (v == ff) continue;
        else {
            dep[v] = dep[n] + 1;
            dfs(v, n);
        }
    }
    out[n] = ++num, seq[num] = n;
}

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

void add(ll x, ll y) {E[++cnt] = {head[x], y}; head[x] = cnt;}
Yukkuri si te yi te ne
原文地址:https://www.cnblogs.com/Gensokyo-Alice/p/13710024.html