ACM-ICPC 2018 焦作赛区网络预赛 E. Jiu Yuan Wants to Eat

Posted sciorz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ACM-ICPC 2018 焦作赛区网络预赛 E. Jiu Yuan Wants to Eat相关的知识,希望对你有一定的参考价值。


分析

除了树剖没想到其他解法。
用线段树维护区间和,同时针对修改区间修改操作建立两个lazy标记,一个是(lazy_{mul}),另一个是(lazy_{add}),代表区间里的数都需要先乘以(lazy_{mul}),再加上(lazy_{add})。如果一个区间需要被重复标记,那么我们可以先把新的lazy标记施加在原有的lazy上。
如果是区间乘以val,那么就可以$ lazy_{mul}=lazy_{mul} imes val,lazy_{add}=lazy_{add} imes val $
对于区间取反操作可以转化成区间乘以-1,然后区间加上(2^{64}-1)

代码

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const ll Mask=-1;
const int maxn=100050;
vector<int> G[maxn];
int sz[maxn],son[maxn],top[maxn],fa[maxn];
int dep[maxn];
void dfs(int x,int par) {
    sz[x]=1;
    fa[x]=par;
    for(auto y:G[x]) {
        if(y!=par) {
            dfs(y,x),sz[x]+=sz[y];
            if(son[x]==0||sz[y]>sz[son[x]]) son[x]=y;
        }
    }
}
int L[maxn],R[maxn],idx[maxn],tot;
void dfs2(int x,int par,int Top) {
    dep[x]=dep[par]+1;
    L[x]=++tot;
    idx[tot]=x;
    top[x]=Top;
    if(son[x]) dfs2(son[x],x,Top);
    for(auto y:G[x]) {
        if(y!=par && y!=son[x]) {
            dfs2(y,x,y);
        }
    }
    R[x]=tot;
}
ll sum[maxn*4],lazy_mul[maxn*4],lazy_add[maxn*4],wid[maxn*4];
void build(int l,int r,int id) {
    lazy_mul[id]=1,lazy_add[id]=0;
    wid[id]=r-l+1;
    sum[id]=0;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(l,mid,id<<1);
    build(mid+1,r,id<<1|1);
}
void pushDown(int id) {
    if(wid[id]==1) {
        lazy_mul[id]=1,lazy_add[id]=0;
        return;
    }
    if(lazy_mul[id]==1&&lazy_add[id]==0) return;
    int x=(id<<1);
    lazy_mul[x]*=lazy_mul[id];
    lazy_add[x]*=lazy_mul[id];
    lazy_add[x]+=lazy_add[id];
    sum[x]=sum[x]*lazy_mul[id]+(lazy_add[id]*wid[x]);

    x=(id<<1|1);
    lazy_mul[x]*=lazy_mul[id];
    lazy_add[x]*=lazy_mul[id];
    lazy_add[x]+=lazy_add[id];
    sum[x]=sum[x]*lazy_mul[id]+(lazy_add[id]*wid[x]);
    lazy_mul[id]=1;
    lazy_add[id]=0;
}
void pushUp(int id) {
    sum[id]=sum[id<<1]+sum[id<<1|1];
}
void mul_update(int x,int y,ll val,int l,int r,int id) {
    pushDown(id);
    if(x<=l && y>=r) {
        lazy_mul[id]*=val;
        lazy_add[id]*=val;
        sum[id]*=val;
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid) mul_update(x,y,val,l,mid,id<<1);
    if(y>mid) mul_update(x,y,val,mid+1,r,id<<1|1);
    pushUp(id);
}
void add_update(int x,int y,ll val,int l,int r,int id) {
    pushDown(id);
    if(x<=l && y>=r) {
        lazy_add[id]+=val;
        sum[id]+=val*wid[id];
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid) add_update(x,y,val,l,mid,id<<1);
    if(y>mid) add_update(x,y,val,mid+1,r,id<<1|1);
    pushUp(id);
}
ll query(int x,int y,int l,int r,int id) {
    // cout<<l<<" "<<r<<" "<<sum[id]<<endl;
    pushDown(id);
    if(x<=l && y>=r) {
        //cout<<"in!
";
        return sum[id];
    }
    int mid=(l+r)>>1;
    ll ans=0;
    if(x<=mid) /*(cout<<"go left
",*/ ans+=query(x,y,l,mid,id<<1);
    if(y>mid) /*cout<<"go right
",*/ ans+=query(x,y,mid+1,r,id<<1|1);
    return ans;
}
int main() {
    int n,q;
    while(scanf("%d", &n)!=EOF) {
        build(1,n,1);
        for(int i = 1; i <= n; ++i) G[i].clear(),sz[i]=top[i]=son[i]=0;
        for(int i = 2; i <= n; ++i) {
            int x;
            scanf("%d", &x);
            G[x].push_back(i);
        }
        scanf("%d", &q);
        tot=0;
        dfs(1,1);
        dfs2(1,1,1);
        while(q--) {
            int t,x,y;
            scanf("%d%d%d", &t,&x,&y);
            ll val;
            if(t==1) {
                scanf("%llu", &val);
                while(top[x]!=top[y]) {
                    if(dep[top[x]]<dep[top[y]]) swap(x,y);
                    mul_update(L[top[x]],L[x],val,1,n,1);
                    x=fa[top[x]];
                }
                if(L[x]>L[y]) swap(x,y);
                mul_update(L[x],L[y],val,1,n,1);
            }
            else if(t==2) {
                scanf("%llu", &val);
                while(top[x]!=top[y]) {
                    if(dep[top[x]]<dep[top[y]]) swap(x,y);
                    add_update(L[top[x]],L[x],val,1,n,1);
                    x=fa[top[x]];
                }
                if(L[x]>L[y]) swap(x,y);
                add_update(L[x],L[y],val,1,n,1);
            }
            else if(t==3) {
                while(top[x]!=top[y]) {
                    if(dep[top[x]]<dep[top[y]]) swap(x,y);
                    mul_update(L[top[x]],L[x],-1,1,n,1);
                    add_update(L[top[x]],L[x],-1,1,n,1);
                    x=fa[top[x]];
                }
                if(L[x]>L[y]) swap(x,y);
                mul_update(L[x],L[y],-1,1,n,1);
                add_update(L[x],L[y],-1,1,n,1);
            }
            else {
                ll ans=0;
                while(top[x]!=top[y]) {
                    if(dep[top[x]]<dep[top[y]]) swap(x,y);
                    ans+=query(L[top[x]],L[x],1,n,1);
                    x=fa[top[x]];
                }
                if(L[x]>L[y]) swap(x,y);
                ans+=query(L[x],L[y],1,n,1);
                printf("%llu
", ans);
            }
        }
    }
    return 0;
}



以上是关于ACM-ICPC 2018 焦作赛区网络预赛 E. Jiu Yuan Wants to Eat的主要内容,如果未能解决你的问题,请参考以下文章

ACM-ICPC 2018 焦作赛区网络预赛 E Jiu Yuan Wants to Eat (树链剖分+线段树)

c_cpp ACM-ICPC 2018焦作赛区网络预赛

ACM-ICPC 2018 焦作赛区网络预赛 B题 Mathematical Curse

ACM-ICPC 2018 焦作赛区网络预赛 Solution

ACM-ICPC 2018 焦作赛区网络预赛 HL

ACM-ICPC 2018 焦作赛区网络预赛 G题 Give Candies