题解 P5528【[Ynoi2012] WC, THUWC, CTSC 与 APIO2017】

Link

题意

子树距离 y(modx) 加,单点求值。

思路

暴力万岁!

考虑将树转化为序列,一个点 i 的子树可表示为 dfn 序列中的一个连续段,设为 li,ri

则原题转化为区间 y(modx) 加,单点求值,这个很像[Ynoi2011] 初始化,没做过的可以做一下。考虑维护差分,然后根号分治,xnvx,yvx,y+vx>n 时暴力加即可。

struct data_structer{
    int val1[sq+10][sq+10],val2[N];
    inline void add(int x,int y,int v){
        if(x<=sq){
            val1[x][y]+=v;
        }else{
            for(int i=y;i<=deep;i+=x){
                val2[i]+=v;
            }
        }
    } 
    inline void clear(int x,int y){
        if(x<=sq){
            val1[x][y]=0;
        }else{
            for(int i=y;i<=deep;i+=x){
                val2[i]=0;
            }
        }
    }
    inline int query(int x){
        int ans=val2[x];
        for(int i=1;i<=sq;i++){
            ans+=val1[i][x%i];
        }
        return ans;
    }
}t;

考虑所有修改对询问的贡献的条件:

  • timei<timej:修改 i 的时间前于询问 j
  • laiajrai:询问点在修改区间内;
  • depajyi+depai(modxi):满足同余条件。

接下来就可以 cdq 做了。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=3e5+10,sq=550;
int cnt,head[N],dep[N],l[N],r[N],deep,tim,ask;
struct Edge{
    int to,nxt;
}a[N];
inline void add(int x,int y){
    cnt++;
    a[cnt].to=y;
    a[cnt].nxt=head[x];
    head[x]=cnt;
} 
inline void dfs(int x){
    tim++;
    l[x]=tim;
    deep=max(deep,dep[x]);
    for(int i=head[x];i;i=a[i].nxt){
        int t=a[i].to;
        dep[t]=dep[x]+1;
        dfs(t);
    }
    r[x]=tim;
}
struct data_structer{
    int val1[sq+10][sq+10],val2[N];
    inline void add(int x,int y,int v){
        if(x<=sq){
            val1[x][y]+=v;
        }else{
            for(int i=y;i<=deep;i+=x){
                val2[i]+=v;
            }
        }
    } 
    inline void clear(int x,int y){
        if(x<=sq){
            val1[x][y]=0;
        }else{
            for(int i=y;i<=deep;i+=x){
                val2[i]=0;
            }
        }
    }
    inline int query(int x){
        int ans=val2[x];
        for(int i=1;i<=sq;i++){
            ans+=val1[i][x%i];
        }
        return ans;
    }
}t;
struct num{
    int pos,x,y,opt,val;
};
int n,m,ans[N];
num b[N<<1],c[N<<1];
inline void cdq(int l,int r){
    if(l==r) return;
    int mid=l+r>>1;
    cdq(l,mid),cdq(mid+1,r);
    int q=l;
    int k=l;
    for(int i=mid+1;i<=r;i++){
        while(b[q].pos<=b[i].pos&&q<=mid){
            if(!b[q].opt)t.add(b[q].x,b[q].y,b[q].val);
            c[k++]=b[q++];
        }
        if(b[i].opt){
            ans[b[i].val]+=t.query(b[i].x);
        }
        c[k++]=b[i];
    }
    for(int i=l;i<q;i++){
        if(!b[i].opt)t.clear(b[i].x,b[i].y);
    }
    for(;q<=mid;)c[k++]=b[q++];
    for(int i=l;i<=r;i++){
        b[i]=c[i];
    }
}
int main(){
    n=read(),m=read();
    for(int i=2;i<=n;i++){
        add(read(),i);
    }
    dfs(1);
    cnt=0;
    for(int i=1;i<=m;i++){
        int opt=read(),a=read();
        switch(opt){
            case 1:{
                int x=read(),y=read(),v=read();
                b[++cnt]=(num){l[a],x,(dep[a]+y)%x,0,v};
                b[++cnt]=(num){r[a]+1,x,(dep[a]+y)%x,0,-v};
                break;
            }
            case 2:{
                b[++cnt]=(num){l[a],dep[a],0,1,++ask};
                break;
            }
        }
    }
    cdq(1,cnt);
    for(int i=1;i<=ask;i++){
        write(ans[i]);
        putc('\n');
    }
    flush();
    return 0;
}

然后您一交,只有 95pts。

我们发现这个算法的时间复杂度为 O(nnlogn),被卡常了。

然后这个做法就不能做了吗?不,我们可以卡常。

linri+nn 时特殊处理,同样根号分治维护,但是可以转换为全局减去未覆盖部分。

然后就能过了。

修改过后的主函数:

int main(){
    n=read(),m=read();
    for(int i=2;i<=n;i++){
        add(read(),i);
    }
    dfs(1);
    cnt=0;
    for(int i=1;i<=m;i++){
        int opt=read(),a=read();
        switch(opt){
            case 1:{
                int x=read(),y=read(),v=read();
                int c=(dep[a]+y)%x;
                if(l[a]<=sq){
                    if(x<=sq){
                        val1[x][c]+=v;
                    }else{
                        for(int i=c;i<=deep;i+=x){
                            val2[i]+=v;
                        }
                    }
                    for(int i=1;i<l[a];i++){
                        if(dep[as[i]]%x==c){
                            val0[as[i]]-=v;
                        }
                    }
                }else{
                    b[++cnt]=(num){l[a],x,c,0,v};
                }
                if(r[a]+sq>=n){
                    for(int i=r[a]+1;i<=n;i++){
                        if(dep[as[i]]%x==c){
                            val0[as[i]]-=v;
                        }
                    }
                }else{
                    b[++cnt]=(num){r[a]+1,x,c,0,-v};
                }
                break;
            }
            case 2:{
                b[++cnt]=(num){l[a],dep[a],0,1,++ask};
                ans[ask]=val0[a]+val2[dep[a]];
                for(int i=1;i<=sq;i++){
                    ans[ask]+=val1[i][dep[a]%i];
                }
                break;
            }
        }
    }
    cdq(1,cnt);
    for(int i=1;i<=ask;i++){
        write(ans[i]);
        putc('\n');
    }
    flush();
    return 0;
}

如果我之后被卡掉了,提醒我一下(

再见 qwq~

posted @   ffffyc  阅读(17)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示