zoukankan      html  css  js  c++  java
  • [GXOI/GZOI2019]旧词

    题目描述

    给定一棵 n 个点的有根树,节点标号1n,1号节点为根。
    给定常数 k。
    给定Q个询问,每次询问给定 x,y
    求:

    $sum_{i leq x}dep[lca(i,y)]^{k}$

    lca(x,y) 表示节点x与节点y在有根树上的最近公共祖先。
    depth(x) 表示节点x的深度,根节点的深度为 1。
    由于答案可能很大,你只需要输出答案模998244353 的结果。

    题解

    先考虑k为1,对于每一对点,只要求lca的深度,而不是lca是谁,那么就有一种奇技淫巧:对于点对(x,y),将x到根的路径上的点打上标记,查询y到根的路径上有多少标记,最终结果就是dep(lca);

    题目要求的式子中i是从(1,x),根据上面的性质,我们可以想到把1∼x的点都这样打上标记,再来查询。

    对于每种询问,我们进行的是相同操作,只是查询时间不同,所以考虑将询问离线,从1∼n依次打标记,每次打完标记,如果当前有查询就查询。

    对于打标记和查询可以看出就是链修改和链查询,所以树链剖分即可。

    那么k≠1呢,考虑还是上面的思路,要怎么给x到根路径上的点打标记,才能使得y查询出来是dep(lca)k;

    很容易想到给深度为i的点标记为ik-(i-1)k,这样查询出来中间一些东西抵消掉最终就是dep(lca)k;

    性质问题就变成了,链修改是每个点要改的权值不同,怎么改?

    可以看到虽然要改的权值不同,但每次一个点要改的权值是固定的,所以对于每个点记录他的基础权值base,每次修改下传修改次数val,对于这个点权值的影响就是val*base;

    这样就能很好地解决这个问题,要注意的是,建树时base也要update。

    //思路:对于本题,求dep[lca(x,y)],在根到x的路径上的点的权值++,最后查询y到根的权值和就是ans
    //至于dep^k,就在深度为d的点权值+d^k-(d-1)^k 
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int maxn=50005;
    const int mod=998244353;
    int n,m,k;
    int fa[maxn],son[maxn],size[maxn],dep[maxn];
    int num,id[maxn],top[maxn],a[maxn];
    int root,ls[maxn<<1],rs[maxn<<1];
    ll sum[maxn<<1],base[maxn<<1],tag[maxn<<1];
    ll get_it[maxn];//ans 
    vector<int> e[maxn];
    vector<pair<int,int> >q[maxn];
    
    template<class T>void read(T &x){
        x=0;char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    }
    
    ll fpow(ll a,ll b){
        ll ans=1;
        while(b){
            if(b&1) ans=ans*a%mod;
            a=a*a%mod;
            b>>=1;
        }
        return ans;
    }
    
    void dfs(int u){
        size[u]=1;
        for(unsigned int i=0;i<e[u].size();i++){
            int v=e[u][i];
            dep[v]=dep[u]+1;
            dfs(v);
            size[u]+=size[v];
            if(size[son[u]]<size[v]) son[u]=v;
        }
    }
    
    void dfs(int u,int tp){
        id[u]=++num;
        a[num]=dep[u];
        top[u]=tp;
        if(!son[u]) return ;
        dfs(son[u],tp);
        for(unsigned int i=0;i<e[u].size();i++){
            int v=e[u][i];
            if(v==son[u]) continue;
            dfs(v,v);
        }
    }
    
    void update(int rt){
        base[rt]=(base[ls[rt]]+base[rs[rt]])%mod;
        sum[rt]=(sum[ls[rt]]+sum[rs[rt]])%mod;
    }
    
    void build(int &rt,int l,int r){
        rt=++num;
        if(l==r){
            base[rt]=((fpow(a[l],k)-fpow(a[l]-1,k))%mod+mod)%mod;
            return ;
        }
        int mid=(l+r)>>1;
        build(ls[rt],l,mid);
        build(rs[rt],mid+1,r);
        update(rt);
    }
    
    void put_tag(int rt,int val){
        tag[rt]+=val;
        if(tag[rt]>=mod) tag[rt]-=mod;
        sum[rt]=(sum[rt]+base[rt]*val%mod)%mod;
    }
    
    void push_down(int rt){
        put_tag(ls[rt],tag[rt]);
        put_tag(rs[rt],tag[rt]);
        tag[rt]=0;
    }
    
    void modify(int rt,int l,int r,int a_l,int a_r){
        if(a_l<=l&&r<=a_r){
            put_tag(rt,1);
            return ;
        }
        if(tag[rt]) push_down(rt);
        int mid=(l+r)>>1;
        if(a_l<=mid) modify(ls[rt],l,mid,a_l,a_r);
        if(mid<a_r) modify(rs[rt],mid+1,r,a_l,a_r);
        update(rt);
    }
    
    void modify(int x,int y){
        while(top[x]!=top[y]){
            modify(1,1,n,id[top[y]],id[y]);
            y=fa[top[y]];
        }
        modify(1,1,n,id[x],id[y]);
    }
    
    ll query(int rt,int l,int r,int a_l,int a_r){
        if(a_l<=l&&r<=a_r) return sum[rt];
        if(tag[rt]) push_down(rt);
        int mid=(l+r)>>1;
        ll ret=0;
        if(a_l<=mid) ret+=query(ls[rt],l,mid,a_l,a_r);
        if(mid<a_r) ret+=query(rs[rt],mid+1,r,a_l,a_r);
        return ret%mod;
    }
    
    ll query(int x,int y){
        ll ret=0;
        while(top[x]!=top[y]){
            ret=(ret+query(1,1,n,id[top[y]],id[y]))%mod;
            //printf("%d %d ",id[top[y]],id[y]);
            y=fa[top[y]]; 
        }
        ret=(ret+query(1,1,n,id[x],id[y]))%mod;
        //printf("%d %d
    ",id[x],id[y]);
        return ret;
    }
    
    int main(){
        read(n);read(m);read(k);
        for(int i=2;i<=n;i++){
            read(fa[i]);
            e[fa[i]].push_back(i);
        }
        for(int i=1;i<=m;i++){
            int x,y;
            read(x);read(y);
            q[x].push_back(make_pair(y,i));
        }
        dep[1]=1;
        dfs(1);
        dfs(1,1);
        num=0;
        build(root,1,n);
        for(int i=1;i<=n;i++){
            modify(1,i);
            for(unsigned int j=0;j<q[i].size();j++)
             get_it[q[i][j].second]=query(1,q[i][j].first);
        }
        for(int i=1;i<=m;i++) printf("%lld
    ",get_it[i]);
    }
    View Code
  • 相关阅读:
    Python脚本文件(.py)打包为可执行文件(.exe)即避免命令行中包含Python解释器
    MVC 三步完成增删改查设计
    MVC中使用SqlServerCe
    回车转Tab
    动态代码
    Mvc 用户没有登录跳转到登录界面
    Mvc
    Mvc提交
    EF查询 linq
    EF数据迁移 Migrations
  • 原文地址:https://www.cnblogs.com/sto324/p/11247041.html
Copyright © 2011-2022 走看看