[GXOI/GZOI2019]旧词

很像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;
}
posted @ 2019-04-25 20:24  Creed-qwq  阅读(225)  评论(0编辑  收藏  举报