spoj 2398 Qtree3

Description

给出一棵树,树节点的颜色初始时为白色,有两种操作:

0 x:把x号节点颜色取反

1 x:询问1到x路径上第一个黑点编号

Solution

最近想练练剖分和线段树,于是想到来做做Qtree系列,不会Lct嘤嘤嘤>_<

这题比较裸,直接剖分然后维护区间最浅的黑色点标号就可以了

注意到把1当做根节点,其实剖分后每个区间左区间显然是更浅的,如果有黑点直接统计答案就可以了

Code

#include <bits/stdc++.h>
using namespace std;
#define ls (rt << 1)
#define rs (rt << 1 | 1)
const int N = 100005;
int n, Q, tot, cnt, to[N << 1], nxt[N << 1], head[N], q[N], num[N], sz[N], top[N], dep[N], pre[N], son[N], id[N], w[N << 2], f[N << 2];
bool vis[N];
inline int read(int &t) {
    int ff = 1;char c;
    while (c = getchar(), c < ‘0‘ || c > ‘9‘) if (c == ‘-‘) ff = -1;
    t = c - ‘0‘;
    while (c = getchar(), c >= ‘0‘ && c <= ‘9‘) t = t * 10 + c - ‘0‘;
    t *= ff;
}
void add(int u, int v) {
    to[tot] = v, nxt[tot] = head[u], head[u] = tot++;
    to[tot] = u, nxt[tot] = head[v], head[v] = tot++;
}
void up(int rt) {
    if (w[ls])  w[rt] = w[ls], f[rt] = f[ls];
    else w[rt] = w[rs], f[rt] = f[rs];
}
void change(int rt, int l, int r, int p) {
    if (l == r) {
        w[rt] ^= 1;
        if (w[rt])  f[rt] = num[l];
        else f[rt] = 0;
        return;
    }
    int mid = l + r >> 1;
    if (p <= mid)   change(ls, l, mid, p);
    else change(rs, mid + 1, r, p);
    up(rt);
}
int query(int rt, int l, int r, int L, int R) {
    if (!w[rt]) return 0;
    if (L <= l && R >= r)   return f[rt];
    int mid = l + r >> 1;
    if (R <= mid)   return query(ls, l, mid, L, R);
    else if (L > mid)   return query(rs, mid + 1, r, L, R);
    else {
        int t = query(ls, l, mid, L, R);
        if (t)  return t;
        return query(rs, mid + 1, r, L, R);
    }
}
int ask(int a, int b) {
    int ans = -1;
    while (top[a] != top[b]) {
        if (dep[top[a]] < dep[top[b]])  swap(a, b);
        int t = query(1, 1, n, id[top[a]], id[a]);
        if (t)  ans = t;
        a = pre[top[a]];
    }
    if (dep[a] < dep[b])    swap(a, b);
    int t = query(1, 1, n, id[b], id[a]);
    if (t)  ans = t;
    return ans;
}
void init() {
    memset(head, -1, sizeof(head));
    read(n), read(Q);
    for (int i = 1, x, y; i < n; ++i) {
        scanf("%d%d", &x, &y);
        add(x, y);
    }
    int r = 0;
    vis[dep[1] = q[0] = 1] = 1;
    for (int i = 0; i <= r; ++i)
        for (int j = head[q[i]]; ~j; j = nxt[j])
            if (!vis[to[j]]){
                vis[to[j]] = 1;
                dep[q[++r] = to[j]] = dep[q[i]] + 1;
                pre[q[r]] = q[i];
            }
    for (int i = r; i >= 0; --i) {
        sz[pre[q[i]]] += ++sz[q[i]];
        if (sz[son[pre[q[i]]]] < sz[q[i]])  son[pre[q[i]]] = q[i];
    }
    for (int i = 0; i <= r; ++i)
        if (!top[q[i]]) {
            for (int j = q[i]; j; j = son[j]) {
                top[j] = q[i];
                num[id[j] = ++cnt] = j;
            }
        }
}
void gao() {
    int op, x;
    for (int i = 1; i <= Q; ++i) {
        read(op), read(x);
        if (!op)    change(1, 1, n, id[x]);
        else    printf("%d\n",ask(1, x));
    }
}
int main() {
    init();
    gao();
    return 0;
}
时间: 2024-11-09 09:06:07

spoj 2398 Qtree3的相关文章

SPOJ QTREE3 - Query on a tree again!

You are given a tree (an acyclic undirected connected graph) with N nodes. The tree nodes are numbered from 1 to N. In the start, the color of any node in the tree is white. We will ask you to perfrom some instructions of the following form: 0 i : ch

SPOJ QTREE3 lct裸题

题目链接 题意: 给定n个点 q个询问 下面n-1行给出树边,点有黑或白色,初始化为白色 下面q行: 询问有2种: 1. 0 x 把x点黑变白,白变黑 2.1 x 询问Path(1,x)路径上第一个黑点的点标, 若不存在黑点则输出-1 思路: lct裸题 #include <iostream> #include <fstream> #include <string> #include <time.h> #include <vector> #inc

SPOJ QTREE系列 树上分治问题。

375.Query on a tree  [QTREE] 有两个操作: (1)修改第i条边的边权 (2)询问a到b路径上的边权最大值. 树链剖分入门题.树链剖分+线段树维护最大值.修改/查询均为O(log^2). 很懒,没有写. 913.Query on a tree II [QTREE2] 有两个操作: (1)询问a到b的距离. (2)询问a到b路径上的第k个点. 很容易想到倍增LCA. 路径上的第k个点,要么是a的第k个父亲,要么是b的第k'个父亲,同样可以倍增实现. 询问都是O(logn)

SPOJ 10232. Distinct Primes

Arithmancy is Draco Malfoy's favorite subject, but what spoils it for him is that Hermione Granger is in his class, and she is better than him at it.  Prime numbers are of mystical importance in Arithmancy, and Lucky Numbers even more so. Lucky Numbe

SPOJ 705 Distinct Substrings(后缀数组)

[题目链接] http://www.spoj.com/problems/SUBST1/ [题目大意] 给出一个串,求出不相同的子串的个数. [题解] 对原串做一遍后缀数组,按照后缀的名次进行遍历, 每个后缀对答案的贡献为n-sa[i]+1-h[i], 因为排名相邻的后缀一定是公共前缀最长的, 那么就可以有效地通过LCP去除重复计算的子串. [代码] #include <cstdio> #include <cstring> #include <algorithm> usi

SPOJ 3273

传送门: 这是一道treap的模板题,不要问我为什么一直在写模板题 依旧只放代码 1 //SPOJ 3273 2 //by Cydiater 3 //2016.8.31 4 #include <iostream> 5 #include <cstring> 6 #include <ctime> 7 #include <cmath> 8 #include <cstdlib> 9 #include <string> 10 #include

SPOJ CRAN02 - Roommate Agreement

题目链接:http://www.spoj.com/problems/CRAN02/ 题目大意:N个数字组成的序列,和为0的连续子序列的个数.N<1e6 解题思路:计算前缀和,统计每个数字出现的次数,那么对于数字sum[i], 如果存在k个sum[i],则代表有C(k, 2)个序列和为0,而如果sum[i] = 0,则还要累加上对应的k值. 代码: 1 ll n; 2 int a[maxn]; 3 ll sum[maxn]; 4 map<int, int> mmp; 5 6 void so

spoj GCJ1C09C Bribe the Prisoners

题目链接: http://www.spoj.com/problems/GCJ1C09C/ 题意: In a kingdom there are prison cells (numbered 1 to P) built to form a straight line segment. Cells number i and i+1 are adjacent, and prisoners in adjacent cells are called "neighbours." A wall wi

SPOJ QTREE Query on a tree ——树链剖分 线段树

[题目分析] 垃圾vjudge又挂了. 树链剖分裸题. 垃圾spoj,交了好几次,基本没改动却过了. [代码](自带常数,是别人的2倍左右) #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 20005 int T,n,fr[maxn],h[maxn],to[maxn],ne[maxn]