zoukankan      html  css  js  c++  java
  • 2020牛客多校(七) A National Pandemic(树链剖分)

    本题最朴素的想法就是对于每个操作,都把他存起来之后查询的时候枚举一下

    虽然这是超时的,但是有一个地方可以借鉴一下,那就是题目中的递推式我们在修改操作的时候,是通过经典的方法也就是w-depth[x]-depth[y]+2*depth[lca(x,y)]这个式子

    我们猜想对于这种题,查询的时候不能线性查询,那如果可以log查询,显然满足条件,对于这种又是树上操作,又是log查询的,应该使用树链剖分比较合理。

    对于这道题,我们可以开三棵线段树来维护答案,第一棵维护w-depth[x],也就是在整个序列加上这个答案,原因是对于每次查询,我们不需要知道到底是谁修改了他,只需要知道修改的内容即可

    第二棵线段树维护depth[y]需要的个数,也就是操作的次数,原因是在修改的时候,我们不可能对于每个其他节点都找到depth[y]对每个更新,因此其实只要在查询的时候知道修改了几次就行

    那么第三个式子,关系到了树上两点,因此使用树链剖分后,直接对于1-x这段路径+1,这样操作查询的时候直接查询1-y就是这个式子的答案,这点在纸上模拟一下就可以发现。

    对于操作:

    第一个操作就是维护三个线段树

    第二个操作其实是单点修改,首先要先查一下答案,看是否已经小于0,如果大于0,就通过单点修改把这个位置的答案变成0,也就是消除前面所有操作的影响

    第三个操作就是把三个线段树的答案合并一下

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=2e5+10;
    int n,m;
    int h[N],ne[N],e[N],idx;
    int son[N],dfn[N],times;
    int sz[N],f[N];
    int top[N],depth[N];
    void add(int a,int b){
        e[idx]=b,ne[idx]=h[a],h[a]=idx++;
    }
    struct node{
        int l,r;
        ll lazy;
        ll sum;
    };
    struct X{
        node tr[N];
        void pushup(int u){
            tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
        }
        void pushdown(int u){
            int x=tr[u].lazy;
            tr[u<<1].lazy+=x;
            tr[u<<1|1].lazy+=x;
            tr[u<<1].sum+=1ll*(tr[u<<1].r-tr[u<<1].l+1)*x;
            tr[u<<1|1].sum+=1ll*(tr[u<<1|1].r-tr[u<<1|1].l+1)*x;
            tr[u].lazy=0;
        }
        void build(int u,int l,int r){
            if(l==r){
                tr[u]={l,r,0,0};
                return ;
            }
            else{
                tr[u]={l,r,0,0};
                int mid=l+r>>1;
                build(u<<1,l,mid);
                build(u<<1|1,mid+1,r);
            }
        }
        void modify(int u,int l,int r,int x){
            if(tr[u].l>=l&&tr[u].r<=r){
                tr[u].lazy+=x;
                tr[u].sum+=1ll*(tr[u].r-tr[u].l+1)*x;
                return ;
            }
            if(tr[u].lazy)
                pushdown(u);
            int mid=tr[u].l+tr[u].r>>1;
            if(l<=mid)
                modify(u<<1,l,r,x);
            if(r>mid)
                modify(u<<1|1,l,r,x);
            pushup(u);
        }
        ll query(int u,int l,int r){
            if(tr[u].l>=l&&tr[u].r<=r){
                return tr[u].sum;
            }
            if(tr[u].lazy){
                pushdown(u);
            }
            int mid=tr[u].l+tr[u].r>>1;
            ll ans=0;
            if(l<=mid){
                ans=query(u<<1,l,r);
            }
            if(r>mid)
                ans+=query(u<<1|1,l,r);
            return ans;
        }
    }st[5];
    void dfs(int u,int fa){
        sz[u]=1;
        for(int i=h[u];i!=-1;i=ne[i]){
            int j=e[i];
            if(j==fa)
                continue;
            depth[j]=depth[u]+1;
            f[j]=u;
            dfs(j,u);
            sz[u]+=sz[j];
            if(sz[j]>sz[son[u]]){
                son[u]=j;
            }
    
        }
    }
    void dfs1(int u,int x){
        dfn[u]=++times;
        top[u]=x;
        if(!son[u])
            return ;
        dfs1(son[u],x);
        for(int i=h[u];i!=-1;i=ne[i]){
            int j=e[i];
            if(j==f[u]||j==son[u])
                continue;
            dfs1(j,j);
        }
    }
    void modify(int x){
        while(x){
            st[0].modify(1,dfn[top[x]],dfn[x],1);
            x=f[top[x]];
        }
    
    }
    ll query(int x){
        ll ans=0;
        while(x){
            ans+=st[0].query(1,dfn[top[x]],dfn[x]);
            x=f[top[x]];
        }
        return ans;
    }
    int get(int x){
        return st[1].query(1,dfn[x],dfn[x])-st[2].query(1,dfn[x],dfn[x])*depth[x]+2*query(x);
    }
    void solve(){
        cin>>n>>m;
        int i;
        memset(h,-1,sizeof h);
        memset(son,0,sizeof son);
        memset(sz,0,sizeof sz);
        memset(depth,0,sizeof depth);
        memset(f,0,sizeof f);
        memset(top,0,sizeof top);
        idx=0,times=0;
        for(i=1;i<n;i++){
            int a,b;
            cin>>a>>b;
            add(a,b);
            add(b,a);
        }
        depth[1]=1;
        dfs(1,-1);
        dfs1(1,1);
        for(i=0;i<3;i++)
            st[i].build(1,1,n);
        while(m--){
            int opt;
            cin>>opt;
            if(opt==1){
                int w,x;
                cin>>x>>w;
                st[1].modify(1,1,n,w-depth[x]);
                st[2].modify(1,1,n,1);
                modify(x);
            }
            else if(opt==2){
                int x;
                cin>>x;
                int ans=get(x);
                if(ans<=0)
                    continue;
                st[1].modify(1,dfn[x],dfn[x],-2*query(x)-st[1].query(1,dfn[x],dfn[x]));
                st[2].modify(1,dfn[x],dfn[x],-st[2].query(1,dfn[x],dfn[x]));
            }
            else{
                int x;
                cin>>x;
                cout<<get(x)<<endl;
            }
        }
    }
    int main(){
        ios::sync_with_stdio(false);
        int t;
        cin>>t;
        while(t--){
            solve();
        }
    }
    View Code

    这份代码只可以通过c++14提交,不然会re,我也不懂为什么,我也是第一次封装了结构体。

  • 相关阅读:
    轻松记账工程冲刺第一天
    课堂练习-找水王
    NABCD模型—轻松记账
    四则运算网页版
    二维数组最大子数组(结对开发)
    软件工程结对作业01
    返回一个二维整数数组中最大联通子数组的和
    学习进度条(第六周)
    整数数组中最大子数组的和
    学习进度条(第五周)
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/13423509.html
Copyright © 2011-2022 走看看