• bzoj 4765: 普通计算姬 主席树+替罪羊树思想


    题目大意:

    给定一棵(n)个节点的带权树有根树,设(sum_p)表示以点(p)为根的这棵子树中所有节点的权
    计算姬支持下列两种操作:

    1. 给定两个整数(u,v),修改点(u)的权值为(v)
    2. 给定两个整数(l,r),计算(sum_{i=l}^rsum_i)

    题解:

    表示自己没能想出来...被同桌嘲讽了QAQ...
    首先是这道题的数据范围很奇怪,只有10W,这就说明了你有充足的时间来瞎搞
    所以我们就瞎搞

    如果没有修改操作那么我们直接(O(n))预处理就可以(O(1))询问了
    但是我们存在修改操作,而且一次修改朴素是(O(n))
    但是我们发现:无论我们要修改多少个数的值,修改的复杂度总是(O(n))

    所以我们多攒几次修改在外部维护其对答案的影响,然后凑够了再一块改.
    所以我们考虑如何外部维护.
    首先我们将问题放到树的dfs序上,

    我们发现:
    这个问题实际上就是让我们统计一下当前询问的sum区间中有多少区间覆盖了我们修改的点

    (注意,每一个sum实际上都代表了dfs序中的一个区间)

    所以我们可以一次枚举每一个点,求一下当前的sum区间中有多少区间覆盖了当前枚举的点.
    对于这个操作我们可以直接用可持久化线段树瞎搞一下就好了

    经过本人的测试:在随机数据下,积累68个修改操作的时候进行修改,跑得最快 !
    本题还有一个大坑点 : 答案会炸long long需要开unsigned long long 才能过...

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    inline void read(int &x){
        x=0;char ch;bool flag = false;
        while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
        while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
    }
    inline void read(ll &x){
        x=0;char ch;bool flag = false;
        while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
        while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
    }
    const int maxn = 100010;
    const int lim = 68;
    struct Node{
        Node *ch[2];
        ll lazy;
    }mem[maxn*50],*it,*null,*root[maxn];
    inline void init(){
        it = mem;null = it++;
        null->ch[0] = null->ch[1] = null;
        null->lazy = 0;root[0] = null;
    }
    Node* insert(Node *rt,int l,int r,int L,int R){
        Node *p = it++;*p = *rt;
        if(L <= l && r <= R){
            p->lazy ++;
            return p;
        }
        int mid = l+r >> 1;
        if(L <= mid) p->ch[0] = insert(p->ch[0],l,mid,L,R);
        if(R >  mid) p->ch[1] = insert(p->ch[1],mid+1,r,L,R);
        return p;
    }
    ll query(Node *p,int l,int r,int pos){
        if(l == r) return p->lazy;
        int mid = l+r >> 1;
        if(pos <= mid) return query(p->ch[0],l,mid,pos) + p->lazy;
        else return query(p->ch[1],mid+1,r,pos) + p->lazy;
    }
    struct Edge{
        int to,next;
    }G[maxn<<1];
    int head[maxn],cnt;
    inline void add(int u,int v){
        G[++cnt].to = v;
        G[cnt].next = head[u];
        head[u] = cnt;
    }
    ll c[maxn],ind[maxn],dfs_clock,oud[maxn];
    #define v G[i].to
    void dfs(int u,int f){
        ind[u] = ++ dfs_clock;
        for(int i = head[u];i;i=G[i].next){
            if(v == f) continue;
            dfs(v,u);
        }oud[u] = dfs_clock;
    }
    #undef v
    struct save{
        ll bef,id,val;
        save(){}
        save(const ll &a,const ll &b,const ll &c){
            bef = a;id = b;val = c;
        }
    }q[maxn];
    int q_siz,n;
    ull a[maxn],sum[maxn];
    inline void rebuild(){
        q_siz = 0;
        memset(a,0,sizeof a);
        for(int i=1;i<=n;++i){
            a[ind[i]] += c[i];
        }
        for(int i=1;i<=n;++i) a[i] += a[i-1];
        for(int i=1;i<=n;++i){
            sum[i] = sum[i-1] + a[oud[i]] - a[ind[i]-1];
        }
    }
    int main(){
        init();
        int m;read(n);read(m);
        for(int i=1;i<=n;++i) read(c[i]);
        int rt = 0;
        for(int i=1,u,v;i<=n;++i){
            read(u);read(v);
            if(u == 0) rt = v;
            else add(u,v),add(v,u);
        }dfs(rt,0);
        for(int i=1;i<=n;++i){
            root[i] = insert(root[i-1],1,n,ind[i],oud[i]);
        }
        rebuild();
        ll op,u,v;
        while(m--){
            read(op);read(u);read(v);
            if(op == 1){
                q[++q_siz] = save(c[u],u,v);
                c[u] = v;   
                if(q_siz == lim) rebuild();
            }else{
                ll l = u,r = v;
                ull ans = sum[v] - sum[u-1];
                for(ll i=1;i<=q_siz;++i){
                    if(q[i].val - q[i].bef > 0) ans += 1ULL*(q[i].val - q[i].bef)*(query(root[r],1,n,ind[q[i].id]) - query(root[l-1],1,n,ind[q[i].id]));
                    if(q[i].val - q[i].bef < 0) ans -= 1ULL*(q[i].bef - q[i].val)*(query(root[r],1,n,ind[q[i].id]) - query(root[l-1],1,n,ind[q[i].id]));
                }
                printf("%llu
    ",ans);
            }
        }
        getchar();getchar();
        return 0;
    }
    
  • 相关阅读:
    1052. 卖个萌 (20)
    1051. 复数乘法 (15)
    1050. 螺旋矩阵(25)
    1049. 数列的片段和(20)
    1048. 数字加密(20)
    1047. 编程团体赛(20)
    1046. 划拳(15)
    怎么用js代码改变单选框的选中状态
    Dom操作--全选反选
    Scoket简介
  • 原文地址:https://www.cnblogs.com/Skyminer/p/6561710.html
Copyright © 2020-2023  润新知