【BZOJ 2588】 Count on a tree

Description

给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。

Input

第一行两个整数N,M。

第二行有N个整数,其中第i个整数表示点i的权值。

后面N-1行每行两个整数(x,y),表示点x到点y有一条边。

最后M行每行两个整数(u,v,k),表示一组询问。

Output

M行,表示每个询问的答案。

Sample Input

8 5
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
0 5 2
10 5 3
11 5 4
110 8 2

Sample Output

2
8
9
105
7

HINT

N,M<=100000

暴力自重。。。

分析:

  可持久化线段树,以父亲的版本为基础创建儿子的版本,结合LCA就可以了。(最后多了个\n居然给我格式错误QAQ)

代码:

  1 #include <cstdio>
  2 #include <algorithm>
  3
  4 const int maxn = 500000;
  5 const int maxm = 2000000;
  6
  7 int et[maxn], ep[maxn], last[maxn], en;
  8 int ch[maxm][2], Count[maxm];
  9 int root[maxm], size;
 10 int n, m, u, v, w, lca, ans;
 11 int deep[maxn], fa[maxn][20];
 12 int num[maxn], id[maxn], back[maxn];
 13
 14 void ins (int a, int b)
 15 {
 16     en++;
 17     ep[en] = last[a];
 18     last[a] = en;
 19     et[en] = b;
 20 }
 21
 22 #define MID (left + (right - left >> 1))
 23
 24
 25 int modify (int left, int right, int pos, int prev)
 26 {
 27     int i = ++size;
 28     if (left < right)
 29     {
 30         int c = pos > MID;
 31         ch[i][!c] = ch[prev][!c];
 32         c ? left = MID + 1 : right = MID;
 33         ch[i][c] = modify (left, right, pos, ch[prev][c]);
 34         Count[i] = Count[ch[i][0]] + Count[ch[i][1]];
 35     }else Count[i] = 1;
 36     return i;
 37 }
 38
 39 #define LEFTSIZE (Count[ch[l1][0]] + Count[ch[l2][0]] - Count[ch[e1][0]] - Count[ch[e2][0]])
 40
 41 int query (int left, int right, int e1, int e2, int l1, int l2, int k)
 42 {
 43     if (left == right) return num[id[left]];
 44     int c = k > LEFTSIZE;
 45     c ? left = MID + 1 : right = MID;
 46     return query (left, right, ch[e1][c], ch[e2][c], ch[l1][c], ch[l2][c], c ? k - LEFTSIZE : k);
 47 }
 48
 49 bool cmp (int a, int b)
 50 {
 51     return num[a] < num[b];
 52 }
 53
 54 void dfs (int i, int p)
 55 {
 56     deep[i] = deep[p] + 1;
 57     fa[i][0] = p;
 58     for (int b = 0; fa[i][b]; b++)
 59         fa[i][b + 1] = fa[fa[i][b]][b];
 60     root[i] = modify (1, n, back[i], root[p]);
 61     for (int e = last[i]; e; e = ep[e])
 62         if (deep[et[e]] == 0) dfs (et[e], i);
 63 }
 64
 65 int find (int i, int j)
 66 {
 67     int k, b;
 68     if (deep[i] > deep[j])
 69         i ^= j, j ^= i, i ^= j;
 70     for (k = deep[j] - deep[i], b = 0; k; k >>= 1, b++)
 71         k & 1 ? j = fa[j][b] : 1;
 72     if (i == j) return i;
 73     for (b = 0; fa[i][b] != fa[j][b]; b++);
 74     for (b--; ~b; b--) if (fa[i][b] != fa[j][b]) i = fa[i][b], j = fa[j][b];
 75     return fa[i][0];
 76 }
 77
 78 int main ()
 79 {
 80     scanf ("%d %d", &n, &m);
 81     for (int i = 1; i <= n; i++)
 82         scanf ("%d", &num[i]), id[i] = i;
 83     std::sort (id + 1, id + n + 1, cmp);
 84     for (int i = 1; i <= n; i++)
 85         back[id[i]] = i;
 86     for (int i = 1; i < n; i++)
 87     {
 88         scanf ("%d %d", &u, &v);
 89         int flag = last[id[1]] > 0;
 90         ins (u, v); ins (v, u);
 91     }
 92     dfs (1, 0);
 93     ans = 0;
 94     for (int i = 0; i < m; i++)
 95     {
 96         scanf ("%d %d %d", &u, &v, &w);
 97         u ^= ans;
 98         lca = find (u, v);
 99         ans = query (1, n, root[fa[lca][0]], root[lca], root[u], root[v], w);
100         if (i) printf ("\n");
101         printf ("%d", ans);
102     }
103 }
时间: 2024-07-31 18:06:43

【BZOJ 2588】 Count on a tree的相关文章

【BZOJ2588】【Spoj 10628.】 Count on a tree 可持久化线段树+lca

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/45048639"); } 题解: 对于每个树上节点存一个版本的可持久化线段树,为它到根节点上所有权值的权值线段树(需要离散化). 然后对于每次询问,这条链(a,b)的线段树就是:线段树a+线段树b?线段树lca?线段树falca 然后

bzoj2589【 Spoj 10707】 Count on a tree II

题目描述 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v),你需要回答u xor lastans和v这两个节点间有多少种不同的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. 输入格式 第一行两个整数N,M. 第二行有N个整数,其中第i个整数表示点i的权值. 后面N-1行每行两个整数(x,y),表示点x到点y有一条边. 最后M行每行两个整数(u,v),表示一组询问. 数据范围是N<=40000 M<=100000 点权在int范围内 输出格式 M行,

【BZOJ 1036】树的统计Count(树链剖分)

[BZOJ 1036]树的统计Count(树链剖分) 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 12991  Solved: 5233 Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权

【BZOJ 2820】 YY的GCD

2820: YY的GCD Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 807  Solved: 404 [Submit][Status] Description 神犇YY虐完数论后给傻×kAc出了一题 给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对 kAc这种傻×必然不会了,于是向你来请教-- 多组输入 Input 第一行一个整数T 表述数据组数 接下来T行,每行两个正整数,表示

【BZOJ 1854】 [Scoi2010]游戏

1854: [Scoi2010]游戏 Time Limit: 5 Sec  Memory Limit: 162 MB Submit: 2609  Solved: 931 [Submit][Status] Description lxhgww最近迷上了一款游戏,在游戏里,他拥有很多的装备,每种装备都有2个属性,这些属性的值用[1,10000]之间的数表示.当他使用某种装备时,他只能使用该装备的某一个属性.并且每种装备最多只能使用一次. 游戏进行到最后,lxhgww遇到了终极boss,这个终极bos

【BZOJ 1036】【ZJOI 2008】树的统计

此题为树链剖分的裸题. 代码如下,使用常用的轻重链剖分. /************************************************************** Problem: 1036 User: Evensgn Language: C++ Result: Accepted Time:2468 ms Memory:5772 kb ****************************************************************/ #inc

【BZOJ 1150】 1150: [CTSC2007]数据备份Backup (贪心+优先队列)

1150: [CTSC2007]数据备份Backup Description 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣.已知办公 楼都位于同一条街上.你决定给这些办公楼配对(两个一组).每一对办公楼可以通过在这两个建筑物之间铺设网 络电缆使得它们可以互相备份.然而,网络电缆的费用很高.当地电信公司仅能为你提供 K 条网络电缆,这意味 着你仅

【BZOJ 2823】 [AHOI2012]信号塔

2823: [AHOI2012]信号塔 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 469  Solved: 198 [Submit][Status][Discuss] Description 在野外训练中,为了确保每位参加集训的成员安全,实时的掌握和收集周边环境和队员信息非常重要,集训队采用的方式是在训练所在地散布N个小型传感器来收集并传递信息,这些传感器只与设在集训地中的信号塔进行通信,信号塔接收信号的覆盖范围是圆形,可以接收到所有分布在

【BZOJ 3190】 [JLOI2013]赛车

3190: [JLOI2013]赛车 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 803 Solved: 279 [Submit][Status][Discuss] Description 这里有一辆赛车比赛正在进行,赛场上一共有N辆车,分别称为个g1,g2--gn.赛道是一条无限长的直线.最初,gi位于距离起跑线前进ki的位置.比赛开始后,车辆gi将会以vi单位每秒的恒定速度行驶.在这个比赛过程中,如果一辆赛车曾经处于领跑位置的话(即没有其他