• 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
  • 相关阅读:
    MVC路由测试
    关于Dapper的使用笔记3
    关于Dapper的使用笔记2
    关于Dapper的使用笔记1
    关于WCF与Autofac的整合
    js获取页面元素距离浏览器工作区顶端的距离
    document.body.scrollTop和document.documentElement.scrollTop 以及值为0的问题
    js实现获取对象key名
    微信小程序分包跳转主包页面
    js禁止页面滚动
  • 原文地址:https://www.cnblogs.com/Gensokyo-Alice/p/13710024.html
Copyright © 2020-2023  润新知