标签: 数据结构

[SPOJ-PT07J]Query on a tree III 题解

[SPOJ-PT07J]Query on a tree III 题解

题目地址:洛谷:【SP1487】PT07J – Query on a tree III – 洛谷、SPOJ:SPOJ.com – Problem PT07J

SPOJ QTREE系列:

题目描述

You are given a node-labeled rooted tree with n nodes.
Define the query (x, k): Find the node whose label is k-th largest in the subtree of the node x. Assume no two nodes have the same labels.
给一棵带点权的以1为根的有根树,查询某子树内点权第k小值。

输入输出格式

输入格式:
The first line contains one integer n (1 <= n <= 105). The next line contains n integers li (0 <= li <= 109) which denotes the label of the i-th node.
Each line of the following n – 1 lines contains two integers u, v. They denote there is an edge between node u and node v. Node 1 is the root of the tree.
The next line contains one integer m (1 <= m <= 104) which denotes the number of the queries. Each line of the next m contains two integers x, k. (k <= the total node number in the subtree of x)

输出格式:
For each query (x, k), output the index of the node whose label is the k-th largest in the subtree of the node x.

输入输出样例

输入样例#1:

5
1 3 5 2 7
1 2
2 3
1 4
3 5
4
2 3
4 1
3 2
3 2

输出样例#1:

5
4
5
5

题解

DFS序+主席树。主席树的叶子节点可以存一下DFS序号,这样方便查。

代码

// Code by KSkun, 2018/3
#include <cstdio>

#include <vector>
#include <algorithm>

typedef long long LL;

inline char fgc() {
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF 
        : *p1++;
}

inline LL readint() {
    register LL res = 0, neg = 1;
    register char c = fgc();
    while(c < '0' || c > '9') {
        if(c == '-') neg = -1;
        c = fgc();
    }
    while(c >= '0' && c <= '9') {
        res = res * 10 + c - '0';
        c = fgc();
    }
    return res * neg;
}

const int MAXN = 100005;

std::vector<int> gra[MAXN];

int dfn[MAXN], ptn[MAXN], siz[MAXN], clk;

inline void dfs(int u, int fa) {
    dfn[u] = ++clk;
    ptn[dfn[u]] = u;
    siz[u] = 1;
    for(int v : gra[u]) {
        if(v == fa) continue;
        dfs(v, u);
        siz[u] += siz[v];
    }
}

struct SGT {
    struct SGTNode {
        int lch, rch, val, dfn;
    } tr[MAXN * 20];
    int rt[MAXN], cnt = 0;

    inline void insert(int &o, int l, int r, int x, int dfn) {
        tr[++cnt] = tr[o]; o = cnt;
        tr[o].val++;
        if(l == r) {
            tr[o].dfn = dfn;
            return;
        }
        int mid = (l + r) >> 1;
        if(x <= mid) insert(tr[o].lch, l, mid, x, dfn);
        else insert(tr[o].rch, mid + 1, r, x, dfn);
    }

    inline int query(int o1, int o2, int l, int r, int k) {
        if(l == r) return ptn[tr[o2].dfn];
        int mid = (l + r) >> 1;
        if(k <= tr[tr[o2].lch].val - tr[tr[o1].lch].val) {
            return query(tr[o1].lch, tr[o2].lch, l, mid, k);
        } else {
            k -= tr[tr[o2].lch].val - tr[tr[o1].lch].val;
            return query(tr[o1].rch, tr[o2].rch, mid + 1, r, k);
        }
    }
} sgt;

int n, m, w[MAXN], ut, vt, xt, kt;
std::vector<int> tmp;

int main() {
    n = readint();
    tmp.push_back(-1);
    for(int i = 1; i <= n; i++) {
        w[i] = readint();
        tmp.push_back(w[i]);
    }
    std::sort(tmp.begin(), tmp.end());
    tmp.erase(std::unique(tmp.begin(), tmp.end()), tmp.end());
    int N = tmp.size() - 1;
    for(int i = 1; i <= n; i++) {
        w[i] = std::lower_bound(tmp.begin(), tmp.end(), w[i]) - tmp.begin();
    }
    for(int i = 1; i < n; i++) {
        ut = readint(); vt = readint();
        gra[ut].push_back(vt);
        gra[vt].push_back(ut);
    }
    dfs(1, 0);
    for(int i = 1; i <= n; i++) {
        sgt.rt[i] = sgt.rt[i - 1];
        sgt.insert(sgt.rt[i], 1, N, w[ptn[i]], i);
    }
    m = readint();
    while(m--) {
        xt = readint(); kt = readint();
        printf("%d\n", sgt.query(sgt.rt[dfn[xt] - 1], sgt.rt[dfn[xt] + siz[xt] - 1], 
            1, N, kt));
    }
    return 0;
}
[SPOJ-QTREE]Query on a tree 题解

[SPOJ-QTREE]Query on a tree 题解

题目地址:洛谷:【SP375】QTREE – Query on a tree – 洛谷、SPOJ:SPOJ.com – Problem QTREE

SPOJ QTREE系列:

题目描述

You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3…N-1.
We will ask you to perfrom some instructions of the following form:

  • CHANGE i ti : change the cost of the i-th edge to ti
  • QUERY a b : ask for the maximum edge cost on the path from node a to node b

给一棵带边权的树,操作1.改边权2.求路径上最大边权。

输入输出格式

输入格式:
The first line of input contains an integer t, the number of test cases (t <= 20). t test cases follow.
For each test case:

  • In the first line there is an integer N (N <= 10000),
  • In the next N-1 lines, the i-th line describes the i-th edge: a line with three integers a b c denotes an edge between a, b of cost c (c <= 1000000),
  • The next lines contain instructions “CHANGE i ti” or “QUERY a b”,
  • The end of each test case is signified by the string “DONE”.

There is one blank line between successive tests.

输出格式:
For each “QUERY” operation, write one integer representing its result.

输入输出样例

输入样例#1:

1

3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE

输出样例#1:

1
3

题解

考虑树链剖分,把每条边的权值记在较深的那个点上即可。剩下的就是板子。注意查询的时候LCA不能计算进去。

代码

// Code by KSkun, 2018/3
#include <cstdio>
#include <cstring>

inline int max(int a, int b) {
    return a > b ? a : b;
}

inline char fgc() {
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}

inline int readint() {
    register int res = 0, neg = 1;
    register char c = fgc();
    while(c < '0' || c > '9') {
        if(c == '-') neg = -1;
        c = fgc();
    }
    while(c >= '0' && c <= '9') {
        res = res * 10 + c - '0';
        c = fgc();
    }
    return res * neg;
}

inline bool isop(char c) {
    return c == 'Q' || c == 'C' || c == 'D';
}

inline char readop() {
    register char c;
    while(!isop(c = fgc()));
    return c;
}

const int MAXN = 10005;

struct Edge {
    int to, w, nxt;
} gra[MAXN << 1];
int head[MAXN], tot;

int T, n, m, ut, vt, wt;
char op;
int w[MAXN], fa[MAXN], siz[MAXN], son[MAXN], dfn[MAXN], ptn[MAXN], top[MAXN], dep[MAXN], cnt;

inline void dfs1(int u) {
    siz[u] = 1;
    son[u] = 0;
    for(register int i = head[u]; i; i = gra[i].nxt) {
        register int v = gra[i].to;
        if(v == fa[u]) continue;
        dep[v] = dep[u] + 1;
        fa[v] = u;
        w[v] = gra[i].w;
        dfs1(v);
        siz[u] += siz[v];
        if(siz[v] > siz[son[u]]) son[u] = v;
    }
}

inline void dfs2(int u, int tp) {
    top[u] = tp;
    dfn[u] = ++cnt;
    ptn[dfn[u]] = u;
    if(son[u]) dfs2(son[u], tp);
    for(register int i = head[u]; i; i = gra[i].nxt) {
        register int v = gra[i].to;
        if(v == son[u] || v == fa[u]) continue;
        dfs2(v, v);
    }
}

int sgt[MAXN << 2];

inline void build(int o, int l, int r) {
    if(l == r) {
        sgt[o] = w[ptn[l]];
        return;
    }
    register int mid = (l + r) >> 1, lch = o << 1, rch = (o << 1) | 1;
    build(lch, l, mid);
    build(rch, mid + 1, r);
    sgt[o] = max(sgt[lch], sgt[rch]);
}

inline void modify(int o, int l, int r, int x, int v) {
    if(l == r) {
        sgt[o] = v;
        return;
    }
    register int mid = (l + r) >> 1, lch = o << 1, rch = (o << 1) | 1;
    if(x <= mid) modify(lch, l, mid, x, v);
    else modify(rch, mid + 1, r, x, v);
    sgt[o] = max(sgt[lch], sgt[rch]);
}

inline int query(int o, int l, int r, int ll, int rr) {
    if(l >= ll && r <= rr) {
        return sgt[o];
    }
    register int mid = (l + r) >> 1, lch = o << 1, rch = (o << 1) | 1, res = 0;
    if(ll <= mid) res = max(res, query(lch, l, mid, ll, rr));
    if(rr > mid) res = max(res, query(rch, mid + 1, r, ll, rr));
    return res;
}

inline int query(int u, int v) {
    register int res = 0, tu = top[u], tv = top[v], t;
    while(tu != tv) {
        if(dep[tu] > dep[tv]) {
            t = tu; tu = tv; tv = t;
            t = u; u = v; v = t;
        }
        res = max(res, query(1, 1, n, dfn[tv], dfn[v]));
        v = fa[tv];
        tv = top[v];
    }
    if(dep[u] > dep[v]) { t = u; u = v; v = t; }
    if(u != v) res = max(res, query(1, 1, n, dfn[u] + 1, dfn[v]));
    return res;
}

struct Edge1 {
    int u, v, w;
} edge[MAXN];

int main() {
    T = readint();
    while(T--) {
        tot = cnt = 0;
        memset(head, 0, sizeof(head));
        n = readint();
        for(int i = 1; i < n; i++) {
            ut = readint(); vt = readint(); wt = readint();
            edge[i] = Edge1 {ut, vt, wt};
            gra[++tot] = Edge {vt, wt, head[ut]};
            head[ut] = tot;
            gra[++tot] = Edge {ut, wt, head[vt]};
            head[vt] = tot;
        }
        dfs1(1);
        dfs2(1, 1);
        build(1, 1, n);
        for(;;) {
            op = readop();
            if(op == 'D') break;
            ut = readint();
            vt = readint();
            if(op == 'Q') {
                printf("%d\n", query(ut, vt));
            } else {
                register int u = dep[edge[ut].u] > dep[edge[ut].v] ? edge[ut].u : edge[ut].v;
                modify(1, 1, n, dfn[u], vt);
            }
        }
    }
    return 0;
}
[IOI2011]Dancing Elephants 题解

[IOI2011]Dancing Elephants 题解

题目地址:CodeChef:Elephant | CodeChef

题目描述

Pattaya 的大象跳舞表演非常有名。整个表演中,N 只大象站成一排跳舞。
经过多年的训练,大象们能够在表演时做很多迷人的舞蹈动作。表演由一系列的动作组成。在每个动作中,只有一只大象可能会移动到一个新的位置上。
大象表演的组织者想要拍摄一本包括全部动作的相册。在每个动作之后,他们要拍摄到所有的大象。
在表演中的任何时刻,多只大象可能站在同一个位置上。在这种情况下,在同一个位置上的大象会从前到后站成一排。
一架相机的拍摄宽度为 L(包括两个端点),即一架相机可以拍摄到位于连续的 L+1 个位置上的大象(有些位置可能没有大象)。因为舞台比较大,所以需要多架相机才能同时拍摄到所有的大象。
在这个题目中,你需要确定每一个动作之后,至少需要多少架相机才能同时拍摄到全部的大象。注意,所需相机的最小数目会随着动作的进行而增加、减少或者保持不变。

输入输出格式

输入格式:
第一行N、M、L。
下面N行表示大象的初始位置。
下面M行一行两个整数,第i只大象到了Pi位置。

输出格式:
每次动作后输出最少相机数。

输入输出样例

输入样例#1:

4 10 5
10
15
17
20
2 16
1 25
3 35
0 38
2 0

输出样例#1:

1
2
2
2
3

输入样例#2:

2 12321 3
2
123
1 76543
0 66321
0 78754

输出样例#2:

2
1
1

说明

1≤N≤150000

题解

如果不改变大象的位置,我们考虑怎么解决。我们从第一只大象开始,每次设置一只摄像机来覆盖L距离内的大象,然后往后找第一只没有被覆盖的大象,再设置相机。最后统计设置了多少相机即可。
现在我们需要改变大象的位置,又不能每一次全部扫一遍,自然需要一个快速统计答案的方法。首先我们考虑一种建图方法,先将所有可能出现大想的位置离散化出来,对于相邻位置连边。每增加一只大象,切断该点与后面的点的边,并且连边至超过L距离的第一个点。将有大象的点的点权设置为1,没有的为0,统计起点到终点的路径点权和即为答案。我们考虑可以用LCT来维护这个图,因为上面不可能有环,每次实际上维护的是一棵树。LCT的功能能够满足我们的需求。

代码

以下代码参考了这个Solution:Solution: 16828126 | CodeChef,感谢原作者kazuma。

// Code by KSkun, 2018/3
#include <cstdio>
#include <cstring>

#include <algorithm>
#include <vector>

inline char fgc() {
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}

inline int readint() {
    register int res = 0, neg = 1;
    char c = fgc();
    while(c < '0' || c > '9') {
        if(c == '-') neg = -1;
        c = fgc();
    }
    while(c >= '0' && c <= '9') {
        res = res * 10 + c - '0';
        c = fgc();
    }
    return res * neg;
}

const int MAXN = 1000005, INF = 1e9;

struct LCTNode {
    int ch[2], fa, val, sum;
    bool rev;
} lct[MAXN];

inline bool isleft(int p) {
    return lct[lct[p].fa].ch[0] == p;
}

inline bool isroot(int p) {
    register int fa = lct[p].fa;
    return lct[fa].ch[0] != p && lct[fa].ch[1] != p;
}

inline void update(int p) {
    register int ls = lct[p].ch[0], rs = lct[p].ch[1];
    lct[p].sum = lct[p].val + lct[ls].sum + lct[rs].sum;
}

inline void reverse(int p) {
    std::swap(lct[p].ch[0], lct[p].ch[1]);
    lct[p].rev ^= 1;
}

inline void pushdown(int p) {
    register int ls = lct[p].ch[0], rs = lct[p].ch[1];
    if(lct[p].rev) {
        if(ls) reverse(ls);
        if(rs) reverse(rs);
        lct[p].rev ^= 1;
    }
}

int sta[MAXN], stop;

inline void pushto(int p) {
    stop = 0;
    while(!isroot(p)) {
        sta[stop++] = p;
        p = lct[p].fa;
    }
    pushdown(p);
    while(stop) {
        pushdown(sta[--stop]);
    }
}

inline void rotate(int p) {
    register bool t = !isleft(p); register int fa = lct[p].fa, ffa = lct[fa].fa;
    lct[p].fa = ffa; if(!isroot(fa)) lct[ffa].ch[!isleft(fa)] = p;
    lct[fa].ch[t] = lct[p].ch[!t]; lct[lct[fa].ch[t]].fa = fa;
    lct[p].ch[!t] = fa; lct[fa].fa = p;
    update(fa);
}

inline void splay(int p) {
    pushto(p);
    for(register int fa = lct[p].fa; !isroot(p); rotate(p), fa = lct[p].fa) {
        if(!isroot(fa)) rotate(isleft(fa) == isleft(p) ? fa : p);
    }
    update(p);
}

inline void access(int p) {
    for(register int q = 0; p; q = p, p = lct[p].fa) {
        splay(p);
        lct[p].ch[1] = q;
        update(p);
    }
}

inline void makert(int p) {
    access(p);
    splay(p);
    reverse(p);
}

inline int findrt(int p) {
    access(p);
    splay(p);
    while(lct[p].ch[0]) p = lct[p].ch[0];
    return p;
}

inline void split(int u, int v) {
    makert(u);
    access(v);
    splay(v);
}

inline void link(int u, int v) {
    split(u, v);
    lct[u].fa = v;
}

inline void cut(int u, int v) {
    split(u, v);
    if(lct[v].ch[0] != u || lct[lct[v].ch[0]].ch[1]) return;
    lct[u].fa = lct[v].ch[0] = 0;
}

inline int query(int u, int v) {
    split(u, v);
    return lct[v].sum;
}

inline void modify(int u, int w) {
    access(u);
    splay(u);
    lct[u].val = w;
    update(u);
}

int n, l, m, p[MAXN], x[MAXN], y[MAXN], cnt[MAXN];
std::vector<int> vec;

int main() {
    n = readint(); l = readint(); m = readint();
    vec.push_back(-1);
    vec.push_back(2e9);
    for(int i = 1; i <= n; i++) {
        p[i] = readint();
        vec.push_back(p[i]);
        vec.push_back(p[i] + l + 1);
    }
    for(int i = 1; i <= m; i++) {
        x[i] = readint() + 1; y[i] = readint();
        vec.push_back(y[i]);
        vec.push_back(y[i] + l + 1);
    }
    std::sort(vec.begin(), vec.end());
    vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
    int siz = vec.size();
    for(int i = 2; i <= siz; i++) {
        link(i - 1, i);
    }
    for(int i = 1; i <= n; i++) {
        int u = std::lower_bound(vec.begin(), vec.end(), p[i]) - vec.begin(),
            v = std::lower_bound(vec.begin(), vec.end(), p[i] + l + 1) - vec.begin();
        if(!cnt[u]) {
            cut(u, u + 1);
            link(u, v);
            modify(u, 1);
        }
        cnt[u]++;
    }
    for(int i = 1; i <= m; i++) {
        int ou = std::lower_bound(vec.begin(), vec.end(), p[x[i]]) - vec.begin(),
            ov = std::lower_bound(vec.begin(), vec.end(), p[x[i]] + l + 1) - vec.begin(),
            u = std::lower_bound(vec.begin(), vec.end(), y[i]) - vec.begin(),
            v = std::lower_bound(vec.begin(), vec.end(), y[i] + l + 1) - vec.begin();
        cnt[ou]--;
        if(!cnt[ou]) {
            cut(ou, ov);
            link(ou, ou + 1);
            modify(ou, 0);
        }
        if(!cnt[u]) {
            cut(u, u + 1);
            link(u, v);
            modify(u, 1);
        }
        cnt[u]++;
        p[x[i]] = y[i];
        printf("%d\n", query(1, siz));
    }
    return 0;
}