• BZOJ 4765 普通计算姬 dfs序+分块+树状数组+好题!!!


    真是道好题。。。感到灵魂的升华。。。


    按dfs序建树状数组,拿前缀和去求解散块;

    按点的标号分块,分成一个个区间,记录区间子树和 的 总和。。。

    具体地,需要记录每个点u修改后,对每一个块i的贡献,记为t[u][i]

    计算思路:dfs时,每到一个新的点,就让++c[其所在块],为了记录每个块中的点出现过几次,就相当于记录这个点 被每一块中的点 包含了几次 , 然后for一遍,记录t[u][i]=c[i]

    当修改一个点时,这个块的和+=这个点u对块i的贡献*这个点的变化量,即sum[i]+=t[u][i]*(v-a[u]);

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #define ll unsigned long long
    #define R register ll
    using namespace std;
    const int N=100010;
    inline ll g() {
        R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
        do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
    }
    int n,m,q,T,cnt,num,rt;
    int vr[N<<1],nxt[N<<1],a[N],fir[N],dfn[N],l[N],r[N],c[320],t[N][320],pos[N];
    ll w[N],sum[320];
    inline void add(int u,int v) {vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
    inline int lbt(int x) {return x&-x;}
    inline void inc(int pos,ll d) {for(;pos<=n;pos+=lbt(pos)) w[pos]+=d;}
    inline ll query(int pos) { R ret=0; 
        for(;pos;pos-=lbt(pos)) 
        ret+=w[pos]; return ret;
    }
    void dfs(int u) { l[u]=++num,++c[pos[u]]; inc(num,a[u]);
        for(R i=1;i<=pos[n];++i) t[u][i]=c[i];
        for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
            if(l[v]) continue; dfs(v);
        } r[u]=num,--c[pos[u]];
    }
    signed main() {
        n=g(),q=g(); T=sqrt(n); m=(n%T)?n/T+1:n/T;
        for(R i=1;i<=n;++i) a[i]=g(); for(R i=1;i<=n;++i) pos[i]=(i-1)/T+1;
        for(R i=1,u,v;i<=n;++i) {u=g(),v=g(); if(!u) rt=v; else add(u,v),add(v,u);}
        dfs(rt); 
        for(R i=1;i<=pos[n];++i) for(R j=(i-1)*T+1,lim=min(i*T,(ll)n);j<=lim;++j) sum[i]+=query(r[j])-query(l[j]-1);
        for(R i=1;i<=q;++i) {
            R k=g(),u=g(),v=g();
            if(k&1) {
                inc(l[u],v-a[u]);
                for(R i=1;i<=pos[n];++i) sum[i]+=1ull*t[u][i]*(v-a[u]);
                a[u]=v;
            } else { R ret=0;
                if(pos[u]==pos[v]) for(R i=u;i<=v;++i) ret+=query(r[i])-query(l[i]-1);
                else {
                    for(R i=u;i<=pos[u]*T;++i) ret+=query(r[i])-query(l[i]-1);
                    for(R i=(pos[v]-1)*T+1;i<=v;++i) ret+=query(r[i])-query(l[i]-1);
                } for(R i=pos[u]+1;i<pos[v];++i) ret+=sum[i]; printf("%llu
    ",ret);        
            }
        }
    }

    这题真神仙。。2019.04.23

  • 相关阅读:
    51nod 最长公共子序列Lcs
    输入挂
    HDU 圆桌会议
    畅通工程
    异形卵
    Python中的多态如何理解?(转帖,让我很理解。)【外加自我看法】(这次修改后应该就是标准答案了)
    Python短路逻辑or的巧妙使用。
    Python三元表达式
    稍微记号下Python的赋值技巧。
    刚看到一个字符串的替换命令,makeslate,记号一下(用处大?应该不算)!
  • 原文地址:https://www.cnblogs.com/Jackpei/p/10758123.html
Copyright © 2020-2023  润新知