很像LNOI 2014 LCA那道题。

同样的套路,离线以后直接扫描线。

k=1的话就是原题。

考虑一般情况。

原本的做法是对x到根的这条链做一下区间+1操作,目的是为了是的在深度为i的位置得到的贡献是i。

因此,我们只需要构造出一个任意一个位置都满足前缀和为i^k的序列即可。

然后每次把这个序列加到这条链上,由于每个点的深度固定,因此每个位置每次增加的数字也是固定的,可以区间打标记线段树维护。

考虑怎么构造这个序列,显然直接把1k,2k,3k,4k......差分就可以了。

#include<bits/stdc++.h>
#define N 220000
#define eps 1e-7
#define inf 1e9+7
#define db double
#define ll long long
#define ldb long double
using namespace std;
inline int read()
{
char ch=0;
int x=0,flag=1;
while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*flag;
}
const int mo=998244353;
int ksm(int x,int k)
{
int ans=1;
while(k)
{
if(k&1)ans=1ll*ans*x%mo;
k>>=1;x=1ll*x*x%mo;
}
return ans;
}
struct edge{int to,nxt;}e[N*2];
int num,head[N];
inline void add(int x,int y){e[++num]={y,head[x]};head[x]=num;}
struct question{int x,y,id;}p[N];
bool cmp(question a,question b){return a.x<b.x;}
int n,q,k,times,v[N],id[N],sz[N],fa[N],dep[N],son[N],top[N],ans[N];
void dfs1(int x,int t)
{
sz[x]=1;dep[x]=t;
for(int i=head[x];i!=-1;i=e[i].nxt)
{
int to=e[i].to;
if(to==fa[x])continue;
dfs1(to,t+1);sz[x]+=sz[to];
if(sz[son[x]]<sz[to])son[x]=to;
}
}
void dfs2(int x,int tp)
{
top[x]=tp;v[++times]=x;id[x]=times;
if(son[x])dfs2(son[x],tp);
for(int i=head[x];i!=-1;i=e[i].nxt)
{
int to=e[i].to;
if(top[to])continue;
dfs2(to,to);
}
}
struct Segment_Tree
{
#define lson o<<1
#define rson o<<1|1
#define mid ((l+r)>>1)
int f[N*4],sumv[N*4],addv[N*4];
inline void pushup(int o)
{
sumv[o]=(sumv[lson]+sumv[rson])%mo;
}
inline void pushdown(int o)
{
addv[lson]=(addv[lson]+addv[o])%mo;
addv[rson]=(addv[rson]+addv[o])%mo;
sumv[lson]=(sumv[lson]+(1ll*addv[o]*f[lson]%mo))%mo;
sumv[rson]=(sumv[rson]+(1ll*addv[o]*f[rson]%mo))%mo;
addv[o]=0;
}
void build(int o,int l,int r)
{
if(l==r)
{
int t=dep[v[l]];
f[o]=(ksm(t,k)-ksm(t-1,k))%mo;
return;
}
build(lson,l,mid);build(rson,mid+1,r);
f[o]=(f[lson]+f[rson])%mo;
}
void optadd(int o,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)
{
addv[o]=(addv[o]+1)%mo;
sumv[o]=(sumv[o]+f[o])%mo;
return;
}
pushdown(o);
if(ql<=mid)optadd(lson,l,mid,ql,qr);
if(qr>mid)optadd(rson,mid+1,r,ql,qr);
pushup(o);
}
int query(int o,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)return sumv[o];
pushdown(o);
int ans=0;
if(ql<=mid)ans=(ans+query(lson,l,mid,ql,qr))%mo;
if(qr>mid)ans=(ans+query(rson,mid+1,r,ql,qr))%mo;
return ans;
}
}T;
void update(int x)
{
while(x)T.optadd(1,1,n,id[top[x]],id[x]),x=fa[top[x]];
}
int query(int x)
{
int ans=0;
while(x)ans=(ans+T.query(1,1,n,id[top[x]],id[x]))%mo,x=fa[top[x]];
return ans;
}
int main()
{
n=read();q=read();k=read();
num=-1;memset(head,-1,sizeof(head));
for(int i=2;i<=n;i++)fa[i]=read(),add(fa[i],i);
dfs1(1,1);dfs2(1,1);T.build(1,1,n);
for(int i=1;i<=q;i++)p[i].x=read(),p[i].y=read(),p[i].id=i;
sort(p+1,p+q+1,cmp);
for(int i=1,j=0;i<=n;i++)
{
update(i);
while(j!=q&&p[j+1].x==i)j++,ans[p[j].id]=query(p[j].y);
}
for(int i=1;i<=q;i++)printf("%d\n",(ans[i]%mo+mo)%mo);
return 0;
}

[GXOI/GZOI2019]旧词的更多相关文章

  1. [LOJ3088][GXOI/GZOI2019]旧词——树链剖分+线段树

    题目链接: [GXOI/GZOI2019]旧词 对于$k=1$的情况,可以参见[LNOI2014]LCA,将询问离线然后从$1$号点开始对这个点到根的路径链修改,每次询问就是对询问点到根路径链查询即可 ...

  2. P5305 [GXOI/GZOI2019]旧词

    题目地址:P5305 [GXOI/GZOI2019]旧词 这里是官方题解 \[\sum_{i \leq x}^{}\ depth(lca(i,y))^k\] \(k = 1\) 求的是 \(\sum_ ...

  3. 【BZOJ5507】[GXOI/GZOI2019]旧词(树链剖分,线段树)

    [BZOJ5507][GXOI/GZOI2019]旧词(树链剖分,线段树) 题面 BZOJ 洛谷 题解 如果\(k=1\)就是链并裸题了... 其实\(k>1\)发现还是可以用类似链并的思想,这 ...

  4. BZOJ5507 GXOI/GZOI2019旧词 (树链剖分+线段树)

    https://www.cnblogs.com/Gloid/p/9412357.html差分一下是一样的问题.感觉几年没写过树剖了. #include<iostream> #include ...

  5. [GXOI/GZOI2019]旧词(树上差分+树剖)

    前置芝士:[LNOI2014]LCA 要是这题放HNOI就好了 原题:\(\sum_{l≤i≤r}dep[LCA(i,z)]\) 这题:\(\sum_{i≤r}dep[LCA(i,z)]^k\) 对于 ...

  6. luogu P5305 [GXOI/GZOI2019]旧词

    传送门 先考虑\(k=1\),一个点的深度就是到根节点的路径上的点的个数,所以\(lca(x,y)\)的深度就是\(x\)和\(y\)到根路径的交集路径上的点的个数,那么对于一个询问,我们可以对每个点 ...

  7. [bzoj5507] [洛谷P5305] [gzoi2019]旧词

    Descriptioin 浮生有梦三千场 穷尽千里诗酒荒 徒把理想倾倒 不如早还乡 温一壶风尘的酒 独饮往事迢迢 举杯轻思量 泪如潮青丝留他方 --乌糟兽/愚青<旧词> 你已经解决了五个问 ...

  8. BZOJ 5507: [gzoi2019]旧词 LCT

    和之前那个 [LNOI]LCA 几乎是同一道题,就是用动态树来维护查分就行. code: #include <bits/stdc++.h> using namespace std; #de ...

  9. [GX/GZOI2019]旧词(树上差分+树剖+线段树)

    考虑k=1的做法:这是一道原题,我还写过题解,其实挺水的,但当时我菜还是看题解的:https://www.cnblogs.com/hfctf0210/p/10187947.html.其实就是树上差分后 ...

随机推荐

  1. java基础语法-char数据类型

    1.java中的char描述了UTF-16中的一个代码单元,因此对于基本的多语言层面可以随意的用char表示 ;//int值只能在0到65535即0000到FFFF 对于其他16个代码级别(两个代码单 ...

  2. mysql之统一刷表

    统一刷表: update report set pdfPath= CONCAT(pdfPath ,substring_index(fileLink, '\\', -1)); update report ...

  3. Arrays工具类

    1.Arrays工具类针对数组进行操作的工具类 提供了排序查找等功能 2.方法: Arrays.toString(int[] a) 将数据转换成字符串 Arrays.sort(int[] a) 将数组 ...

  4. github一些事

    我的个人github地址是:https://github.com/BUGDuYu 我们开发团队小组的github地址是: https://github.com/APPdoctrine 资源推荐: gi ...

  5. MTK-TP(电阻屏校准程序ts_lib移植)

    现今的项目中已经很少有使用电阻TP,但总有些奇怪的需求.如果项目中遇到需要校准电阻屏如何保证较快且较稳的调试TP呢.这里介绍使用ts_lib库来进行调试. 当然也可以使用一些常见的校准算法,采集5点, ...

  6. MTK-TP(触屏)解读一

    MTK中的TP代码结构并不复杂,相比于其他的系统更为的简单些.它使用的是input子系统,通过该系统来上报触摸按键. 首先我们来看看TP的文件夹下的各代码文件的功能. 文件名 具体功能 关系文件 tp ...

  7. Type Conversion

    文章著作权归作者所有.转载请联系作者,并在文中注明出处,给出原文链接. 本文原更新于作者的github博客,这里给出链接. 什么是转换 转换是接受一个类型的值并使用它作为另一个类型的等价值的过程.转换 ...

  8. python 包 笔记

    绝对导入和相对导入 我们的最顶级包glance是写给别人用的,然后在glance包内部也会有彼此之间互相导入的需求,这时候就有绝对导入和相对导入两种方式: 绝对导入:以glance作为起始 相对导入: ...

  9. freeswitch reloadxml 出错

    1.修改fs配置文件后,reloadxml控制台上报错误. 2,控制台日志显示 error near line 7301]:missing>] 查询 log 下的 freeswitch.xml. ...

  10. vector某元素是否存在、查找指定元素 、去重

    vector.map 判断某元素是否存在.查找指定元素 [C++]判断元素是否在vector中,对vector去重,两个vector求交集.并集 PS:注意重载