LOJ#3088. 「GXOI / GZOI2019」旧词(树剖+线段树)

题面

传送门

题解

先考虑\(k=1\)的情况,我们可以离线处理,从小到大对于每一个\(i\),令\(1\)到\(i\)的路径上每个节点权值增加\(1\),然后对于所有\(x=i\)的询问查一下\(y\)到根节点的路径和就是了

那么\(k\neq 1\)的情况该怎么办呢?我们来考虑一下令\(1\)到\(i\)的路径上每个节点权值加\(1\)的本质,相当于是令每个节点\(u\)增加\({dep_u}^k-{dep_{fa_u}}^k\),那么用树剖+线段树维护就行了

//minamoto
#include<bits/stdc++.h>
#define R register
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=E[i].v;i;i=E[i].nx,v=E[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
char sr[1<<21],z[20];int K=-1,Z=0;
inline void Ot(){fwrite(sr,1,K+1,stdout),K=-1;}
void print(R int x){
    if(K>1<<20)Ot();if(x<0)sr[++K]='-',x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++K]=z[Z],--Z);sr[++K]='\n';
}
const int N=1e5+5,P=998244353;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
    R int res=1;
    for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
    return res;
}
struct eg{int v,nx;}E[N];int head[N],tot;
inline void Add(R int u,R int v){E[++tot]={v,head[u]},head[u]=tot;}
struct node;typedef node* ptr;
struct node{
    ptr lc,rc;int sum,s,t;
    inline node();
    inline void ppd(R int x){sum=add(sum,mul(s,x)),t+=x;}
    inline void pd(){if(t)lc->ppd(t),rc->ppd(t),t=0;}
    inline void upd(){sum=add(lc->sum,rc->sum);}
}e[N<<2],*rt;int cnt;
inline node::node(){lc=rc=e;}
int dfn[N],rk[N],bin[N],h[N],dep[N],top[N],fa[N],sz[N],son[N],tim,res,n,q,k;
void dfs1(int u){
    sz[u]=1,dep[u]=dep[fa[u]]+1;
    go(u){
        dfs1(v),sz[u]+=sz[v];
        if(sz[v]>sz[son[u]])son[u]=v;
    }
}
void dfs2(int u,int t){
    top[u]=t,dfn[u]=++tim,rk[tim]=bin[dep[u]];
    if(!son[u])return;dfs2(son[u],t);
    go(u)if(v!=son[u])dfs2(v,v);
}
void build(ptr &p,int l,int r){
    p=e+(++cnt);if(l==r)return p->s=rk[l],void();
    int mid=(l+r)>>1;
    build(p->lc,l,mid),build(p->rc,mid+1,r);
    p->s=add(p->lc->s,p->rc->s);
}
void update(ptr p,int l,int r,int ql,int qr){
    if(ql<=l&&qr>=r)return p->ppd(1),void();
    int mid=(l+r)>>1;p->pd();
    if(ql<=mid)update(p->lc,l,mid,ql,qr);
    if(qr>mid)update(p->rc,mid+1,r,ql,qr);
    p->upd();
}
void query(ptr p,int l,int r,int ql,int qr,int d){
    if(ql<=l&&qr>=r)return res=add(res,add(p->sum,mul(d,p->s))),void();
    int mid=(l+r)>>1;d+=p->t;
    if(ql<=mid)query(p->lc,l,mid,ql,qr,d);
    if(qr>mid)query(p->rc,mid+1,r,ql,qr,d);
}
void change(int u){while(top[u])update(rt,1,n,dfn[top[u]],dfn[u]),u=fa[top[u]];}
int query(int u){res=0;while(top[u])query(rt,1,n,dfn[top[u]],dfn[u],0),u=fa[top[u]];return res;}
struct qwq{
    int p,u,id;
    inline bool operator <(const qwq &b)const{return p<b.p;}
}st[N];int ans[N];
int main(){
//  freopen("testdata.in","r",stdin);
    n=read(),q=read(),k=read();
    for(R int i=2;i<=n;++i)fa[i]=read(),Add(fa[i],i);
    fp(i,1,n)bin[i]=ksm(i,k);
    fd(i,n,1)bin[i]=dec(bin[i],bin[i-1]);
    dfs1(1),dfs2(1,1),build(rt,1,n);
    fp(i,1,q)st[i].p=read(),st[i].u=read(),st[i].id=i;
    sort(st+1,st+1+q);
    for(R int i=1,j=1;i<=n;++i){
        change(i);
        while(j<=q&&st[j].p<=i)ans[st[j].id]=query(st[j].u),++j;
    }
    fp(i,1,q)print(ans[i]);
    return Ot(),0;
}
上一篇:QR码与DM码的区别


下一篇:QueryRunner类的八种结果处理集