[GXOI/GZOI2019]旧词

很像LNOI 2014 LCA那道题。

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

k=1的话就是原题。

考虑一般情况。

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

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

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

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

#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;
}

猜你喜欢

转载自www.cnblogs.com/Creed-qwq/p/10770733.html