[GXOI/GZOI2019]旧词(树上差分+树剖)
前置芝士:[LNOI2014]LCA
要是这题放HNOI就好了
原题:\(\sum_{l≤i≤r}dep[LCA(i,z)]\)
这题:\(\sum_{i≤r}dep[LCA(i,z)]^k\)
对于原题,我们需要把每个询问拆成1~l-1 & 1r再进行差分(所以这题帮我们省去了一个步骤~)
先考虑\(k=1\)原题
我们先转化题意
\(dep[lca]\)$\ \(==\)\ $$dis[1][lca]+1$$\ \(==\)\ $$lca->1$的点数
所以我们每一个点(x)对答案的贡献(\(dep[lca(x, z)]\)),就是他们到根节点的公共路径的点数
于是,对于每一个点,我们只需要把1->x的链上加1即可
对于每一个询问,我们只需要求出1->z的链上的和即可
这一点我们可以利用树剖\(/LCT\)解决
但是直接做是\(O(N^2*\)树剖\(\LCT)\)的,我们考虑莫队
这样复杂度变成了\(O(N\sqrt{N}*\)树剖\(\LCT)\)
什么?你觉得这个算法还不够优秀?所以我们来考虑优化莫队
莫队的\(\sqrt{N}\)是怎么来的?不停的移动左右端点
但是这道题的左端点是固定的\((1)\),所以只需要移动右端点即可,而右端点不需要动来动去,只需要往后扫一遍即可,复杂度是\(O(N*\)树剖\(\LCT)\)
代码的话可以参考[LNOI2014]LCA
考虑k!=1
我们为什么k=1的时候对于每个点是\(1->x\)路径上+1?
这个1的本质是树上差分,即:\((dep[x]+1)^1-dep[x]^1 = 1\)
所以我们只需要把1改成k即可
所以现在问题变成了:给定一个序列,每一个点有两个权值\((a, b)\),每一个点的点权为\(a*b\),支持a权值区间加1和区间查询
因为b不会改变,所以我们考虑线段树
把线段树的每一个节点新弄一个权值,为\(\sum_{l≤i≤r} b\),每次更新区间的时候用这个权值*sum即可
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define re register
#define debug printf("Now is Line : %d\n",__LINE__)
#define file(a) freopen(#a".in","r",stdin);freopen(#a".out","w",stdout)
#define int long long
#define inf 123456789
#define mod 998244353
il int read() {
re int x = 0, f = 1; re char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
return x * f;
}
#define rep(i, s, t) for(re int i = s; i <= t; ++ i)
#define Next(i, u) for(re int i = head[u]; i; i = e[i].next)
#define mem(k, p) memset(k, p, sizeof(k))
#define ls k * 2
#define rs k * 2 + 1
#define _ 500005
struct edge {int v, next;}e[_];
struct ques {
int u, z, id;
il bool operator < (const ques x) const {return u < x.u;}
}q[_];
int n, m, k, val[_ << 2], sum[_ << 2], mi[_], head[_], cnt, ans[_], tag[_ << 2], now;
int fa[_], dep[_], size[_], son[_], top[_], seg[_], col, rev[_];
il void add(int u, int v) {
e[++ cnt] = (edge) {v, head[u]}, head[u] = cnt;
}
il int qpow(int a, int b) {
int r = 1;
while(b) {
if(b & 1) r = 1ll * r * a % mod;
b >>= 1, a = 1ll * a * a % mod;
}
return r;
}
il void dfs1(int u) {
dep[u] = dep[fa[u]] + 1, size[u] = 1;
Next(i, u) {
if(e[i].v == fa[u]) continue;
dfs1(e[i].v), size[u] += size[e[i].v];
if(size[son[u]] < size[e[i].v]) son[u] = e[i].v;
}
}
il void dfs2(int u, int fr) {
top[u] = fr, seg[u] = ++ col, rev[col] = u;
if(son[u]) dfs2(son[u], fr);
Next(i, u) if(e[i].v != son[u] && e[i].v != fa[u]) dfs2(e[i].v, e[i].v);
}
il void build(int k, int l, int r) {
if(l == r) return (void)(val[k] = (mi[dep[rev[l]]] - mi[dep[rev[l]] - 1] + mod) % mod);
int mid = (l + r) >> 1;
build(ls, l, mid), build(rs, mid + 1, r), val[k] = (val[ls] + val[rs]) % mod;
}
il void pushdown(int k) {
if(!tag[k]) return;
sum[ls] = (sum[ls] + ((tag[k] * val[ls]) % mod)) % mod;
sum[rs] = (sum[rs] + ((tag[k] * val[rs]) % mod)) % mod;
tag[ls] += tag[k], tag[rs] += tag[k], tag[k] = 0;
}
il void change(int k, int l, int r, int ll, int rr) {
if(l > rr || ll > r) return;
if(l >= ll && r <= rr) {sum[k] = (sum[k] + val[k]) % mod, ++ tag[k]; return;}
int mid = (l + r) >> 1;
pushdown(k), change(ls, l, mid, ll, rr), change(rs, mid + 1, r, ll, rr);
sum[k] = (sum[ls] + sum[rs]) % mod;
}
il int query(int k, int l, int r, int ll, int rr) {
if(l > rr || ll > r) return 0;
if(l >= ll && r <= rr) return sum[k];
int mid = (l + r) >> 1;
pushdown(k);
return (query(ls, l, mid, ll, rr) + query(rs, mid + 1, r, ll, rr)) % mod;
}
il int query(int u) {
int ans = 0;
while(top[u]) ans = (ans + query(1, 1, n, seg[top[u]], seg[u])) % mod, u = fa[top[u]];
return ans;
}
il void change(int u) {
while(top[u]) change(1, 1, n, seg[top[u]], seg[u]), u = fa[top[u]];
}
signed main() {
n = read(), m = read(), k = read() % (mod - 1), now = 1;
rep(i, 1, n) mi[i] = qpow(i, k);
rep(i, 2, n) fa[i] = read(), add(fa[i], i);
rep(i, 1, m) q[i].id = i, q[i].u = read(), q[i].z = read();
sort(q + 1, q + m + 1), dfs1(1), dfs2(1, 1), build(1, 1, n);
rep(i, 1, n) {
change(i);
while(i == q[now].u) ans[q[now].id] = query(q[now].z), ++ now;
}
rep(i, 1, m) printf("%lld\n", ans[i]);
return 0;
}
[GXOI/GZOI2019]旧词(树上差分+树剖)的更多相关文章
- 【BZOJ5507】[GXOI/GZOI2019]旧词(树链剖分,线段树)
[BZOJ5507][GXOI/GZOI2019]旧词(树链剖分,线段树) 题面 BZOJ 洛谷 题解 如果\(k=1\)就是链并裸题了... 其实\(k>1\)发现还是可以用类似链并的思想,这 ...
- [LOJ3088][GXOI/GZOI2019]旧词——树链剖分+线段树
题目链接: [GXOI/GZOI2019]旧词 对于$k=1$的情况,可以参见[LNOI2014]LCA,将询问离线然后从$1$号点开始对这个点到根的路径链修改,每次询问就是对询问点到根路径链查询即可 ...
- P5305 [GXOI/GZOI2019]旧词
题目地址:P5305 [GXOI/GZOI2019]旧词 这里是官方题解 \[\sum_{i \leq x}^{}\ depth(lca(i,y))^k\] \(k = 1\) 求的是 \(\sum_ ...
- [GX/GZOI2019]旧词(树上差分+树剖+线段树)
考虑k=1的做法:这是一道原题,我还写过题解,其实挺水的,但当时我菜还是看题解的:https://www.cnblogs.com/hfctf0210/p/10187947.html.其实就是树上差分后 ...
- BZOJ5507 GXOI/GZOI2019旧词 (树链剖分+线段树)
https://www.cnblogs.com/Gloid/p/9412357.html差分一下是一样的问题.感觉几年没写过树剖了. #include<iostream> #include ...
- luogu P5305 [GXOI/GZOI2019]旧词
传送门 先考虑\(k=1\),一个点的深度就是到根节点的路径上的点的个数,所以\(lca(x,y)\)的深度就是\(x\)和\(y\)到根路径的交集路径上的点的个数,那么对于一个询问,我们可以对每个点 ...
- 洛谷P3258 [JLOI2014]松鼠的新家(树上差分+树剖)
题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前 ...
- [GXOI/GZOI2019]旧词
很像LNOI 2014 LCA那道题. 同样的套路,离线以后直接扫描线. k=1的话就是原题. 考虑一般情况. 原本的做法是对x到根的这条链做一下区间+1操作,目的是为了是的在深度为i的位置得到的贡献 ...
- P3250 [HNOI2016] 网络 (树剖+堆/整体二分+树上差分+树状数组)
解法1: 本题有插入路径和删除路径,在每个节点维护插入堆和删除堆,查询时两者top一样则一直弹出.如果每个节点维护的是经过他的路径,显然有些不好处理,正难则反,每个点维护不经过他的路径,那么x节点出了 ...
随机推荐
- java中求质数(素数)的问题
这篇笔记讲讲关于java中质数的问题. 一.什么是质数(素数)? 定义:质数又称素数.一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数:否则称为合数.它可以有无限个数. 二.ja ...
- 20190422-外部导入CSS样式之link、CSS@import、Sass分音
写在前面乱七八糟的前言:今天wuliMR黄问了一个问题,Sass的分音与link标签都是导入外部样式的,有什么不同,这真是个好问题,因为本白着实没想过,也不知道,不过没关系,成功的背后总有一个默默无闻 ...
- maven+springMVC(一)
[目录]
- 智能指针std::unique_ptr
std::unique_ptr 1.特性 1) 任意时刻只能由一个unique_ptr指向某个对象,指针销毁时,指向的对象也会被删除(通过内置删除器,通过调用析构函数实现删除对象) 2)禁止拷贝和赋值 ...
- 从零学习Fluter(六):Flutter仿boss直聘v1.0重构
今天继续学习flutter,觉得这个优秀的东西,许多方面还需要完善,作为一个后来者,要多向别人学习.俗话说,“学无先后,达者为师”.今天呢,我又重新把flutter_boss这个项目代码 从头到脚看了 ...
- 使用Server Trigger保护重要的数据库对象
一 .Server Trigger的简单介绍 在SQL Server数据库中,Server Trigger 是一种特殊类型的存储过程,它可以对特定表.视图或存储中的必然事件自动响应,不由用户调用.创建 ...
- js 发送短信倒计时、秒杀倒计时实现代码
<!doctype html> <html> <head> <meta charset="utf-8"> <meta name ...
- 好程序员web前端分享HTML基本结构和基本语法
HTML基本结构和HTML基本语法 HTML基本结构 HTML的基本语法 1.<常规标记><标记 属性=“属性值” 属性=“属性值”></标记> 标记也可叫标签或叫 ...
- 小功能 HTML标签状态改变
在编写程序得时候根据不同的业务需求会改变相应的标签的状态 今天介绍一下<a>标签状态的改变 当前业务场景为需要A标签的样式 即保留A标签的原有样式 在鼠标悬停得时候鼠标状态呈销售状 都知道 ...
- Airtest自动化测试工具
一开始知道Airtest大概是在年初的时候,当时,看了一下官方的文档,大概是类似Sikuli的一个工具,主要用来做游戏自动化的,通过截图的方式用来解决游戏自动化测试的难题.最近,移动端测试的同事尝试用 ...