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
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){
        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,我也不懂为什么,我也是第一次封装了结构体。

 

你可能感兴趣的:(2020牛客多校(七) A National Pandemic(树链剖分))