QTREE 5 - Query on a tree V

Published on 2016-03-18

题目地址

分析

链分治,不过要注意这个题目由于是求最短路径,而且没有边权,所以不用担心走到上面的链之后又走下来,那样如果下面的链有答案的话,只会更长!

代码

//  Created by Sengxian on 3/17/16.
//  Copyright (c) 2016年 Sengxian. All rights reserved.
//  Spoj QTREE V 链分治
#include <algorithm>
#include <iostream>
#include <cassert>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
#include <set>
using namespace std;

inline int ReadInt() {
    int n = 0, ch = getchar();
    while(!isdigit(ch)) ch = getchar();
    while(isdigit(ch)) n = (n << 3) + (n << 1) + ch - '0', ch = getchar();
    return n;
}

const int maxn = 100000 + 3, INF = 0x3f3f3f3f;
vector<int> G[maxn];
int n = 0, blackCnt = 0;
bool color[maxn]; // 0 - black 1 - white

//datas
int fa[maxn], s[maxn], id[maxn], idR[maxn], bel[maxn], timestamp = 0, sz[maxn]; //sz[i] 为以 i 为根的线段树的大小
int root[maxn]; //链头的线段树节点标号
//end

//seg dates
static const int maxNode = (1 << 17) * 2 + 10;
struct Node {
    int minL, minR;
    Node(int minL = INF, int minR = INF): minL(minL), minR(minR) {} 
}segs[maxNode];
int ls[maxNode], rs[maxNode];
int segCnt = 0;
//end
multiset<int> ch[maxn];

int dfs1(int u, int f) {
    fa[u] = f, s[u] = 1;
    for (int i = 0; i < (int)G[u].size(); ++i) {
        int v = G[u][i];
        if (v != f) s[u] += dfs1(v, u);
    }
    return s[u];
}

void dfs2(int u, int num) {
    idR[timestamp] = u, id[u] = timestamp++, bel[u] = num;
    sz[num]++;
    int Max = 0, idx = -1;
    for (int i = 0; i < (int)G[u].size(); ++i) {
        int v = G[u][i];
        if (v != fa[u] && s[v] > Max) {Max = s[v], idx = v;}
    }
    if (Max == 0) return;
    dfs2(idx, num);
    for (int i = 0; i < (int)G[u].size(); ++i) {
        int v = G[u][i];
        if (v != fa[u] && v != idx) dfs2(v, v);
    }
}

Node merge(const Node &lnode, const Node &rnode, int l, int r) {
    int mid = (l + r) / 2;
    Node newNode;
    newNode.minL = min(lnode.minL, rnode.minL + mid - l);
    newNode.minR = min(rnode.minR, lnode.minR + r - mid);
    return newNode;
}

void maintain(int o, int u) {
    int d = INF;
    if (color[u] == 1) d = 0;
    if(ch[u].size()) d = min(d, *(ch[u].begin()));
    segs[o].minL = segs[o].minR = d;
}

void buildTree(int o, int l, int r) {
    if (r - l == 1) {
        int u = idR[l];
        for (int i = 0; i < (int)G[u].size(); ++i) {
            int v = G[u][i];
            if (v != fa[u] && bel[u] != bel[v]) {
                buildTree(root[v] = segCnt++, id[v], id[v] + sz[v]);
                ch[u].insert(segs[root[v]].minL + 1);
            }
            maintain(o, u);
        }
    }else {
        int mid = (l + r) / 2;
        buildTree(ls[o] = segCnt++, l, mid);
        buildTree(rs[o] = segCnt++, mid, r);
        segs[o] = merge(segs[ls[o]], segs[rs[o]], l, r);
    }
}

void process() {
    dfs1(0, -1);
    dfs2(0, 0);
    buildTree(root[0] = segCnt++, id[0], id[0] + sz[0]);
}

int query(int o, int l, int r, int target) {
    //cout << o << ' ' << l << ' ' << r << ' ' << target << endl;
    int ans = INF;
    if (r - l == 1) {
        int head = bel[target], fh = fa[head];
        ans = segs[o].minL; //到下面的链
        if (bel[target] != 0) {
            //到上面的链,由于是最小值,不用担心再次跑到本链!
            ans = min(ans,
            query(root[bel[fh]], id[bel[fh]], id[bel[fh]] + sz[bel[fh]], fh) + id[target] - id[head] + 1);
        }
    }else {
        int mid = (l + r) / 2;
        if (id[target] < mid) {
            ans = min(ans, segs[rs[o]].minL + mid - id[target]);
            ans = min(ans, query(ls[o], l, mid, target));
        }else {
            ans = min(ans, segs[ls[o]].minR + id[target] - mid + 1);
            ans = min(ans, query(rs[o], mid, r, target));
        }
    }
    return ans;
}

vector<int> path;
void findPath(int u) {
    while (u != -1) {
        path.push_back(u);
        u = fa[bel[u]];
    }
}

void modify(int o, int l, int r, int i) {
    if (r - l == 1) {
        int u = idR[l];
        if (i + 1 != (int)path.size()) {
            int nexT = bel[path[i + 1]];
            ch[u].erase(ch[u].find(segs[root[nexT]].minL + 1));
            modify(root[nexT], id[nexT], id[nexT] + sz[nexT], i + 1);
            ch[u].insert(segs[root[nexT]].minL + 1);
        }
        maintain(o, u);
    }else {
        int mid = (l + r) / 2;
        if (id[path[i]] < mid) modify(ls[o], l, mid, i);
        else modify(rs[o], mid, r, i);
        segs[o] = merge(segs[ls[o]], segs[rs[o]], l, r);
    }
}

int main() {
    //freopen("test.in", "r", stdin);
    blackCnt = n = ReadInt();
    memset(color, 0, sizeof(bool) * n);
    for (int i = 0; i < n - 1; ++i) {
        int f = ReadInt() - 1, t = ReadInt() - 1;
        G[f].push_back(t);
        G[t].push_back(f);
    }
    process();
    int q = ReadInt();
    while (q--) {
        int op = ReadInt();
        if (op == 0) {
            int u = ReadInt() - 1;
            if (color[u]) blackCnt++;
            else blackCnt--;
            color[u] = !color[u];
            path.clear();
            findPath(u);
            reverse(path.begin(), path.end());
            modify(root[0], id[0], id[0] + sz[0], 0);
        }else if(op == 1) {
            int u = ReadInt() - 1;
            if (blackCnt == n) puts("-1");
            else printf("%d\n", query(root[bel[u]], id[bel[u]], id[bel[u]] + sz[bel[u]], u));
        }else assert(false);
    }
    return 0;
}