[OJ#63]树句节够提

试题描述

给定一棵节点数为 N 的有根树,其中 1 号点是根节点,除此之外第 i 个节点的父亲为 fi。每个节点有一个权值 Ai,所有边权均为 1。

给定 Q 个询问,每个询问以一个二元组 (x,k) 的形式给出,表示询问以 x 为根的子树内,与 x 距离至少为 k 的所有节点权值之和。

由于输出量可能过大,我们使用以下方式减少输出量。

void print(int q, long long* ans, int lim) {
for(int i = 1; i <= q; ) {
long long res = 0;
for(int j = i; j <= min(q, i + lim - 1); j++) res ^= ans[j];
i += lim;
printf("%lld\n", res);
}
}

程序中 ansi 表示第 i 次询问的答案,你需要在你的程序末尾调用以上函数来输出答案。

输入

第一行为一个正整数 N。

第二行为 N 个正整数 Ai

第三行为 N−1 个正整数 fi,第 i 个正整数表示 i+1 的父亲节点。

第四行为一个正整数 Q。

接下来 Q 行每行两个整数 x、k。

最后一行为一个正整数 lim。

输出

在你的程序末尾调用以上函数来输出答案。

输入示例


输出示例


数据规模及约定

对于 20% 的数据,1≤N,Q≤2501

对于 70% 的数据,1≤N,Q≤252501

对于 100% 的数据,1≤N,Q≤2525010,1≤Ai≤52501,1≤fi≤i−1,1≤x,k+1,lim≤N

保证单个输出文件大小不超过 0.5MB,但如果你需要使用Hack功能,请保证Max(1,floor(N/10000))≤lim。

题解

注意:此题标算 O(n)。

长链剖分“新”用法?(就好像之前写过长链剖分的题一样。。。)

先离线,将所有询问放入树上对应节点,然后给树进行长链剖分(其实长链剖分主要目的是将“长链”放到区间的连续一段)。然后在处理询问时,因为对于一个子树 x,深度一样的节点地位一样,所以可以将子树的信息全都“压缩”到长链上,由于长链是这个子树 x 中一端在 x 上的最长链,所以能够保证所有的节点都有地方存。

由于一条长链对应一段连续区间,在询问某个深度的时候就可以 O(1) 用数组查询了。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std; int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 2525020
#define LL long long int n, q, fa[maxn], m, head[maxn], nxt[maxn], to[maxn], A[maxn]; void AddEdge(int a, int b) {
to[++m] = b; nxt[m] = head[a]; head[a] = m;
return ;
} int dep[maxn], mxd[maxn], son[maxn], pos[maxn], clo;
void build(int u) {
mxd[u] = dep[u];
for(int e = head[u]; e; e = nxt[e]) {
dep[to[e]] = dep[u] + 1;
build(to[e]);
mxd[u] = max(mxd[u], mxd[to[e]]);
if(!son[u] || mxd[to[e]] > mxd[son[u]]) son[u] = to[e];
}
return ;
}
void gett(int u) {
pos[u] = ++clo;
if(son[u]) gett(son[u]);
for(int e = head[u]; e; e = nxt[e]) if(to[e] != son[u]) gett(to[e]);
return ;
} struct Que {
int head[maxn], nxt[maxn], dep[maxn];
Que() { memset(head, 0, sizeof(head)); }
void Insert(int u, int d, int id) {
dep[id] = d; nxt[id] = head[u]; head[u] = id;
return ;
}
} que;
LL sum[maxn], Ans[maxn];
void solve(int u) {
if(son[u]) solve(son[u]);
for(int e = head[u]; e; e = nxt[e]) if(to[e] != son[u]) {
solve(to[e]);
for(int i = 0; i <= mxd[to[e]] - dep[to[e]]; i++)
sum[pos[u]+1+i] += sum[pos[to[e]]+i];
}
sum[pos[u]] = (son[u] ? sum[pos[son[u]]] : 0) + A[u];
for(int e = que.head[u]; e; e = que.nxt[e])
Ans[e] = (que.dep[e] <= mxd[u] - dep[u]) ? sum[pos[u]+que.dep[e]] : 0;
return ;
} void print(int q, int lim) {
for(int i = 1; i <= q; ) {
long long res = 0;
for(int j = i; j <= min(q, i + lim - 1); j++) res ^= Ans[j];
i += lim;
printf("%lld\n", res);
}
return ;
} int main() {
n = read();
for(int i = 1; i <= n; i++) A[i] = read();
for(int i = 2; i <= n; i++) {
fa[i] = read();
AddEdge(fa[i], i);
} build(1);
gett(1); q = read();
for(int i = 1; i <= q; i++) {
int x = read(), d = read();
que.Insert(x, d, i);
}
solve(1); print(q, read()); return 0;
}

然而这题我写的 O(nlogn) 的算法比上面的 O(n) 要快 233333

注意不能直接强上主席树,因为空间不够。

考虑到每个询问就是问子树内深度大于等于某个值(k+dep[x],k 表示该询问的参数,dep[x] 表示该询问中节点 x 的深度,不妨称每个询问的 k+dep[x] 为它的绝对深度)的所有的点权和,所以我们将询问按它们的绝对深度从大到小排序,然后依次处理。那么问题变成每次添加一个点,然后询问区间和,可以用树状数组很快地实现。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std; const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
if(Head == Tail) {
int l = fread(buffer, 1, BufferSize, stdin);
Tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
} #define maxn 2525020
#define LL long long int n, q, fa[maxn], m, head[maxn], nxt[maxn], to[maxn], A[maxn]; void AddEdge(int a, int b) {
to[++m] = b; nxt[m] = head[a]; head[a] = m;
return ;
} struct Level {
int head[maxn], nxt[maxn];
Level() { memset(head, 0, sizeof(head)); }
void Insert(int u, int level) {
nxt[u] = head[level];
head[level] = u;
return ;
}
} lev;
int dep[maxn], dl[maxn], dr[maxn], clo;
void build(int u) {
dl[u] = ++clo;
lev.Insert(u, dep[u]);
for(int e = head[u]; e; e = nxt[e]) {
dep[to[e]] = dep[u] + 1;
build(to[e]);
}
dr[u] = clo;
return ;
} struct Que {
int u, d, id;
Que() {}
Que(int _1, int _2, int _3): u(_1), d(_2 + dep[u]), id(_3) {}
bool operator < (const Que& t) const { return d < t.d; }
} qs[maxn]; LL C[maxn];
void add(int x, int v) {
for(; x <= n; x += x & -x) C[x] += v;
return ;
}
LL que(int x) {
LL sum = 0;
for(; x; x -= x & -x) sum += C[x];
return sum;
} LL Ans[maxn]; int num[100], cntn;
void putnum(LL x) {
cntn = 0;
while(x) num[cntn++] = x % 10, x /= 10;
for(int i = cntn - 1; i >= 0; i--) putchar(num[i] + '0');
if(!cntn) putchar('0');
putchar('\n');
return ;
} void print(int q, int lim) {
for(int i = 1; i <= q; ) {
long long res = 0;
for(int j = i; j <= min(q, i + lim - 1); j++) res ^= Ans[j];
i += lim;
putnum(res);
}
return ;
} int main() {
n = read();
for(int i = 1; i <= n; i++) A[i] = read();
for(int i = 2; i <= n; i++) {
fa[i] = read();
AddEdge(fa[i], i);
} build(1);
q = read();
for(int i = 1; i <= q; i++) {
int x = read(), k = read();
qs[i] = Que(x, k, i);
}
sort(qs + 1, qs + q + 1);
for(int i = q, j = n; i; i--) {
while(j >= qs[i].d) {
for(int e = lev.head[j]; e; e = lev.nxt[e]) add(dl[e], A[e]);
j--;
}
Ans[qs[i].id] = que(dr[qs[i].u]) - que(dl[qs[i].u] - 1);
} print(q, read()); return 0;
}

此题略丧病。。。

[OJ#63]树句节够提的更多相关文章

  1. Zijian-lv #3 树句节狗提

    如你所见,这是一道狗题 一棵树,多次询问与一个点距离至少为 $k$ 的点的权值和 $n,q \leq 2525010$ sol: 长链剖分 需要注意的是这道题卡空间 我把我所有的 vector 换成链 ...

  2. Java实现二叉搜索树的添加,前序、后序、中序及层序遍历,求树的节点数,求树的最大值、最小值,查找等操作

    什么也不说了,直接上代码. 首先是节点类,大家都懂得 /** * 二叉树的节点类 * * @author HeYufan * * @param <T> */ class Node<T ...

  3. 题解西电OJ (Problem 1004 -亚特兰提斯)--最小生成树

    Description 为了找寻沉睡的亚特兰提斯大陆,wm来到了大西洋上进行探险,找了半个月仍一无所获.然而在一次突袭而来的暴风雨后,wm的船莫名地驶入了一片未知的区域,发现了一个地图上未标记的岛屿, ...

  4. [SCOI2014]方伯伯的OJ(线段树)

    方伯伯正在做他的Oj.现在他在处理Oj上的用户排名问题.Oj上注册了n个用户,编号为1-n“,一开始他们按照编号排名. 方伯伯会按照心情对这些用户做以下四种操作,修改用户的排名和编号: 1.操作格式为 ...

  5. 覆盖的面积 HDU - 1255 (线段树-扫描线)模板提

    给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1& ...

  6. BZOJ4811 Ynoi2017由乃的OJ(树链剖分+线段树)

    先考虑NOI2014的水题,显然从高位到低位贪心,算一下该位取0和1分别得到什么即可. 加强这个水题,变成询问区间.那么线段树维护该位取0和1从左到右和从右到左走完这个节点表示的区间会变成什么即可,也 ...

  7. SDUT OJ 字典树 AND 静态内存与动态内存

    字典树 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Problem Description 遇到单词不认识怎么办? 查字典 ...

  8. 入门OJ:最短路径树入门

    题目描述 n个城市用m条双向公路连接,使得任意两个城市都能直接或间接地连通.其中城市编号为1..n,公路编号为1..m.任意个两个城市间的货物运输会选择最短路径,把这n*(n-1)条最短路径的和记为S ...

  9. hdoj 1856 More is better【求树的节点数】

    More is better Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 327680/102400 K (Java/Others) ...

随机推荐

  1. 卓越管理的秘密(Behind Closed Doors)

    或许提到本书甚至本书的作者Johanna Rothman我们会感到些许陌生,那么提起她的另一本获得素有软件界奥斯卡之称的Jolt生产效率大奖的名著<项目管理修炼之道>,会不会惊讶的发现,原 ...

  2. HDU 5452 Minimum Cut (Spaning Tree)

    生成树的上的一个非根结点对应一条生成树上的边,然后这个结点的子树上连出去的边就对应去掉这条边的割, 然后就可以对树外的边求LCA,在LCA上标记,利用这个信息可以算出有多少条边在子树上,以及有多少条边 ...

  3. [Java] 新手快速就业需要掌握的知识点

    目的:主要是分享下日常工作中使用到的技术点,根据二八定律快速掌握使用知识点,先就业再沉淀去积累经验.(个人建议仅供参考) 背景:目前一般来说,都是前后端分离.你只需要提供接口给前端,他来处理就可以了, ...

  4. 学习JavaScript你必须掌握的8大知识点!

    大知识点! 一.JavaScript思维导图之<变量>的学习 二.    JavaScript思维导图之<函数基础>  三.JavaScript思维导图之<基本dom操作 ...

  5. console.log与console.dir的区别

    今天学习promise的时候看到了console.dir这个方法,感到很好奇,查了以下感觉又长知识了 在Chrome中,控制台对象定义了两个似乎做同样事情的方法: console.log() cons ...

  6. 【转】EM算法原理

    EM是我一直想深入学习的算法之一,第一次听说是在NLP课中的HMM那一节,为了解决HMM的参数估计问题,使用了EM算法.在之后的MT中的词对齐中也用到了.在Mitchell的书中也提到EM可以用于贝叶 ...

  7. ANSI C 与 K&R C

    C语言由Dennis M.Ritchie在1973年设计和实现.从那以后使用者逐渐增加.到1978年Ritchie和Bell实验室的另一位程序专家Kernighan合写了著名的<TheC Pro ...

  8. 洛谷 P2717 寒假作业

    https://www.luogu.org/problemnew/show/P2717 $n \le 1004枚举区间,挨个计算,判断,时间复杂度$O(n^3)$. $n \le 5000$,预处理出 ...

  9. [BZOJ] 1907: 树的路径覆盖

    一个点必然被路径覆盖,根据是否为路径的端点分类 \(f[x][0]\)表示以\(x\)为根的子树,\(x\)不为端点的最小路径覆盖数 \(f[x][1]\)表示以\(x\)为根的子树,\(x\)为一条 ...

  10. pandas中层次化索引与切片

    Pandas层次化索引 1. 创建多层索引 隐式索引: 常见的方式是给dataframe构造函数的index参数传递两个或是多个数组 Series也可以创建多层索引 Series多层索引 B =Ser ...