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

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

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 50010
#define P 998244353
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,q,k,fa[N],p[N],w[N],ans[N],t;
int dfn[N],id[N],size[N],deep[N],top[N],son[N],cnt;
int tree[N<<2],lazy[N<<2],L[N<<2],R[N<<2],s[N<<2];
struct data{int to,nxt;
}edge[N];
struct data2
{
	int x,y,i;
	bool operator <(const data2&a) const
	{
		return x<a.x; 
	}
}Q[N];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
int ksm(int a,int k)
{
	int s=1;
	for (;k;k>>=1,a=1ll*a*a%P) if (k&1) s=1ll*s*a%P;
	return s; 
}
void dfs1(int k)
{
	size[k]=1;
	for (int i=p[k];i;i=edge[i].nxt)
	{
		deep[edge[i].to]=deep[k]+1;
		dfs1(edge[i].to);
		size[k]+=size[edge[i].to];
		if (size[edge[i].to]>size[son[k]]) son[k]=edge[i].to;
	}
}
void dfs2(int k,int from)
{
	dfn[k]=++cnt;id[cnt]=k;top[k]=from;
	if (son[k]) dfs2(son[k],from);
	for (int i=p[k];i;i=edge[i].nxt)
	if (edge[i].to!=son[k]) dfs2(edge[i].to,edge[i].to);
}
void build(int k,int l,int r)
{
	L[k]=l,R[k]=r;
	if (l==r) {s[k]=w[deep[id[l]]];return;}
	int mid=l+r>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	s[k]=(s[k<<1]+s[k<<1|1])%P;
}
void update(int k,int x)
{
	lazy[k]+=x;
	tree[k]=(tree[k]+1ll*x*s[k])%P;
}
void down(int k)
{
	update(k<<1,lazy[k]);
	update(k<<1|1,lazy[k]);
	lazy[k]=0;
}
void add(int k,int l,int r)
{
	if (L[k]==l&&R[k]==r) {update(k,1);return;}
	if (lazy[k]) down(k);
	int mid=L[k]+R[k]>>1;
	if (r<=mid) add(k<<1,l,r);
	else if (l>mid) add(k<<1|1,l,r);
	else add(k<<1,l,mid),add(k<<1|1,mid+1,r);
	tree[k]=(tree[k<<1]+tree[k<<1|1])%P;
}
int query(int k,int l,int r)
{
	if (L[k]==l&&R[k]==r) return tree[k];
	if (lazy[k]) down(k);
	int mid=L[k]+R[k]>>1;
	if (r<=mid) return query(k<<1,l,r);
	else if (l>mid) return query(k<<1|1,l,r);
	else return (query(k<<1,l,mid)+query(k<<1|1,mid+1,r))%P;
}
void ins(int x)
{
	while (x)
	{
		add(1,dfn[top[x]],dfn[x]);
		x=fa[top[x]];
	}
}
int get(int x)
{
	int s=0;
	while (x)
	{
		s=(s+query(1,dfn[top[x]],dfn[x]))%P;
		x=fa[top[x]];
	}
	return s;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("bzoj5507.in","r",stdin);
	freopen("bzoj5507.out","w",stdout);
	const char LL[]="%I64d\n";
#else
	const char LL[]="%lld\n";
#endif
	n=read(),q=read(),k=read();
	for (int i=2;i<=n;i++)
	{
		fa[i]=read();
		addedge(fa[i],i);
	}
	for (int i=0;i<=n;i++) w[i]=ksm(i,k);
	for (int i=n;i>=1;i--) w[i]=(w[i]-w[i-1]+P)%P;
	deep[1]=1;dfs1(1);dfs2(1,1);
	build(1,1,n);
	for (int i=1;i<=q;i++) Q[i].x=read(),Q[i].y=read(),Q[i].i=i;
	sort(Q+1,Q+q+1);
	int cur=0;
	for (int i=1;i<=q;i++)
	{
		while (cur<Q[i].x) ins(++cur);
		ans[Q[i].i]=get(Q[i].y);
	}
	for (int i=1;i<=q;i++) printf("%d\n",ans[i]);
	return 0;
}

  

posted @ 2019-04-17 21:39  Gloid  阅读(163)  评论(0编辑  收藏  举报