• Luogu 3242 [HNOI2015]接水果


    BZOJ4009 权限题

    真的不想再写一遍了

    大佬blog

    假设有果实$(x, y)$,询问$(a, b)$,用$st_i$表示$i$的$dfs$序,用$ed_i$表示所有$i$的子树搜完的$dfs$序,那么果实对询问产生贡献只会有两种情况:

    1、这个果实表示的区间是一条链

      不妨假设$dep_x < dep_y$,记$z$为$x$到$y$的树链上的从$x$向下走的第一个点,画个图可以发现$(a, b)$需要满足:

        $st_a in [1, st_z - 1] cup [ed_z + 1, n], st_b in [st_y, ed_y]$,其中$(a, b)$可以互换。

    2、这个果实表示的链是一条先向上再向下的纯正的树链

      仍然画个图发现$(a, b)$需要满足:$st_a in [st_x, ed_x], st_b in [st_y, ed_y]$, $(a, b)$仍然可以互换。

    对于每一个询问$(a, b)$,只要看一看有多少果实满足上面两种选一种的条件,然后求个$k$小就好了。

    发现这其实是一个在二维矩阵中动态加点求$k$小的问题,这时候$KDTree$就出现了,然而我不会……

    考虑扫描线降维,一个矩阵根据$x$坐标拆成两条线然后排个序扫一扫,每一次根据询问的点的位置进行加入删除的调整然后求个$k$小就好了。

    也就是说只要写一个支持在一条线上区间加区间减然后求$k$小的数据结构就好了,我们需要一个外层权值内层下标的线段树兹磁这个操作。

    瓶颈在于树套树的$O(nlog^2n)$。

    最好标记永久化一下。

    Code:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N = 4e4 + 5;
    const int M = 3e7 + 5;
    const int Lg = 18;
    
    int n, m, qn, lcnt = 0, mx = 0, num[N], tot = 0, head[N];
    int dfsc = 0, st[N], ed[N], fa[N][Lg], dep[N], ans[N];
    
    struct Edge {
        int to, nxt;
    } e[N << 1];
    
    inline void add(int from, int to) {
        e[++tot].to = to;
        e[tot].nxt = head[from];
        head[from] = tot;
    }
    
    struct Line {
        int pos, x, y, v, type;
        
        inline Line (int nowPos = 0, int nowX = 0, int nowY = 0, int nowV = 0, int nowType = 0) {
            pos = nowPos, x = nowX, y = nowY, v = nowV, type = nowType;
        }
        
        friend bool operator < (const Line &u, const Line &v) {
            return u.pos < v.pos;
        }
        
    } a[N << 3];
    
    inline void addLine(int l1, int r1, int l2, int r2, int v) {
        a[++lcnt] = Line(l1, l2, r2, v, 1);
        a[++lcnt] = Line(r1 + 1, l2, r2, v, -1);
    }
    
    struct Querys {
        int x, y, k, id;
        
        friend bool operator < (const Querys &u, const Querys &v) {
            return u.x < v.x;    
        }
        
    } q[N];
    
    inline void read(int &X) {
        X = 0; char ch = 0; int op = 1;
        for(; ch > '9' || ch < '0'; ch = getchar())
            if(ch == '-') op = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    inline void swap(int &x, int &y) {
        int t = x; x = y; y = t;
    }
    
    void dfs(int x, int fat, int depth) {
        fa[x][0] = fat, dep[x] = depth, st[x] = ++dfsc;
        for(int i = 1; i <= 16; i++)
            fa[x][i] = fa[fa[x][i - 1]][i - 1];
        for(int i = head[x]; i; i = e[i].nxt) {
            int y = e[i].to;
            if(y == fat) continue;
            dfs(y, x, depth + 1);
        }
        ed[x] = dfsc;
    }
    
    inline int getPos(int x, int stp) {
        int res = x;
        for(int i = 16; i >= 0; i--)
            if((stp >> i) & 1) res = fa[res][i];
        return res;
    }
    
    namespace InSegT {
        struct Node {
            int lc, rc, sum;
        } s[M];
        
        int nodeCnt = 0;
        
        #define lc s[p].lc
        #define rc s[p].rc
        #define sum(p) s[p].sum
        #define mid ((l + r) >> 1)
        
        void modify(int &p, int l, int r, int x, int y, int v) {
            if(!p) p = ++nodeCnt;
            
            if(x <= l && y >= r) {
                sum(p) += v;
                return;
            }
            
            if(x <= mid) modify(lc, l, mid, x, y, v);
            if(y > mid) modify(rc, mid + 1, r, x, y, v);
        }
        
        int query(int p, int l, int r, int x) {
            if(l == r) return sum(p);
            int res = sum(p);
            if(x <= mid) res += query(lc, l, mid, x);
            else res += query(rc, mid + 1, r, x);
            return res;
        }
        
        #undef lc
        #undef rc
        #undef sum
    }
    
    namespace OutSegT {
        using namespace InSegT;
        
        #define lc p << 1
        #define rc p << 1 | 1 
        
        int root[N << 2];
        
        void ins(int p, int l, int r, int x, int y, int pos, int type) {
            modify(root[p], 1, n, x, y, type);
            if(l == r) return;
            
            if(pos <= mid) ins(lc, l, mid, x, y, pos, type);
            else ins(rc, mid + 1, r, x, y, pos, type);
        }
        
        int getKth(int p, int l, int r, int x, int k) {
            if(l == r) return l;
            int now = query(root[lc], 1, n, x);
            if(k <= now) return getKth(lc, l, mid, x, k);
            else return getKth(rc, mid + 1, r, x, k - now);
        }
        
    } using namespace OutSegT;
    
    int main() {
        read(n), read(m), read(qn);
        for(int x, y, i = 1; i < n; i++) {
            read(x), read(y);
            add(x, y), add(y, x);
        }
        dfs(1, 0, 1);
        
        for(int x, y, v, i = 1; i <= m; i++) {
            read(x), read(y), read(v);
            num[++mx] = v;
            if(dep[x] > dep[y]) swap(x, y);
            if(st[x] <= st[y] && ed[x] >= ed[y]) {
                int z = getPos(y, dep[y] - dep[x] - 1);
                if(ed[z] < n) {
                    addLine(st[y], ed[y], ed[z], n, v);
                    addLine(ed[z], n, st[y], ed[y], v);            
                }
                if(st[z] > 1) {
                    addLine(st[y], ed[y], 1, st[z] - 1, v);
                    addLine(1, st[z] - 1, st[y], ed[y], v);    
                }
            } else {
                addLine(st[x], ed[x], st[y], ed[y], v);
                addLine(st[y], ed[y], st[x], ed[x], v);
            }
        }
        
        sort(num + 1, num + mx + 1);
        mx = unique(num + 1, num + 1 + mx) - num - 1;
        for(int i = 1; i <= lcnt; i++)
            a[i].v = lower_bound(num + 1, num + mx + 1, a[i].v) - num;
        
        for(int i = 1; i <= qn; i++) {
            read(q[i].x), read(q[i].y), read(q[i].k);
            q[i].x = st[q[i].x], q[i].y = st[q[i].y];
            q[i].id = i;
        }    
        
        sort(q + 1, q + 1 + qn);
        sort(a + 1, a + 1 + lcnt);
        for(int j = 1, i = 1; i <= qn; i++) {
            for(; j <= lcnt && a[j].pos <= q[i].x; ++j)
                ins(1, 1, mx, a[j].x, a[j].y, a[j].v, a[j].type);
            ans[q[i].id] = getKth(1, 1, mx, q[i].y, q[i].k);
        }
        
        for(int i = 1; i <= qn; i++)
            printf("%d
    ", num[ans[i]]);
        
        return 0;
    }
    View Code
  • 相关阅读:
    Scala(二)——基础语法(与Java的区分)和函数式编程
    LeetCode3.无重复字符的最大子串
    LeetCode2.两数相加
    LeetCode1.两数之和
    Scala(一)——基本类型
    图论算法总结(一)——图的遍历
    Hutool强大的工具类
    Jdk8新特性之接口新增方法
    mybatis的xml配置中if text判断
    Jdk8新特性目录
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9918046.html
Copyright © 2020-2023  润新知