• cf1110F 离线+树上操作+线段树区间更新


    自己搞的算法超时了。。但是思路没什么问题:用线段树维护每个点到叶子节点的距离即可

    /*
    线段树维护区间最小值,每次向下访问,就把访问到的点对应的区间段减去边权
    到另一颗子树访问时,向上回溯时加上减去的边权即可;
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long 
    #define maxn 500050
    #define INF 0x3f3f3f3f3f3f3f3f
    struct Query{
        int x,l,r,id;
        bool operator<(const Query &y)const{return x<y.x;}
    }Q[maxn];
    int q,n,fa[maxn],r[maxn],leaf[maxn];
    ll dep[maxn],w[maxn],ans[maxn];
    
    /*线段树部分*/
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    ll Min[maxn<<2],add[maxn<<2];
    inline void pushup(int rt){Min[rt]=min(Min[rt<<1],Min[rt<<1|1])+add[rt];}
    
    void build(int l,int r,int rt){
        add[rt]=0;
        if(l==r){Min[rt]=leaf[l]?dep[l]:INF;return;}//不是叶子节点就是无限大 
        int m=l+r>>1;
        build(lson);
        build(rson);
        pushup(rt);
    }
    void Add(int L,int R,int l,int r,int rt,int val){
        if(L<=l && R>=r){
            add[rt]+=val;Min[rt]+=val;return;
        }
        int m=l+r>>1;
        if(L<=m) Add(L,R,lson,val);
        if(R>m) Add(L,R,rson,val);
        pushup(rt);
    }
    ll query(int L,int R,int l,int r,int rt){
        if(L<=l && R>=r)return Min[rt];
        int m=l+r>>1;
        ll res=INF;
        if(L<=m)res=min(res,query(L,R,lson));
        if(R>m)res=min(res,query(L,R,rson));
        return res+add[rt];
    }
    
    int main(){
        cin>>n>>q;
        memset(leaf,1,sizeof leaf);
        for(int i=1;i<=n;i++)r[i]=i;
        for(int i=2;i<=n;i++){
            cin>>fa[i]>>w[i];
            leaf[fa[i]]=0;
            dep[i]=dep[fa[i]]+w[i];
        }
        for(int i=n;i>=2;i--)
            r[fa[i]]=max(r[fa[i]],r[i]);
        for(int i=0;i<q;i++)
            cin>>Q[i].x>>Q[i].l>>Q[i].r,Q[i].id=i;
        sort(Q,Q+q);
    
        build(1,n,1);
        int x=1,qi=0;//从根开始遍历
        ll offset=0;//用来记录回溯的
        while(1){
            while(Q[qi].x==x && qi<q){
                ans[Q[qi].id]=query(Q[qi].l,Q[qi].r,1,n,1)+offset;
                ++qi;
            }
            if(x<n){
                int y=x+1;
                while(x!=fa[y]){
                    Add(x,r[x],1,n,1,2*w[x]);
                    offset-=w[x]; x=fa[x];
                }
                x=y;
                Add(x,r[x],1,n,1,-2*w[x]);
                offset+=w[x];
            }
            else break;
        }
        for(int i=0;i<q;i++)printf("%lld
    ",ans[i]);
    }

    这是cf上的代码

    #include<bits/stdc++.h>
    #define maxn 1000005
    #define F first
    #define S second
    using namespace std;
    typedef long long ll;
    const ll INF=1e18;
    typedef pair<ll,ll> pi;
    typedef pair<int,pi> pii;
    vector <pi> h[maxn];
    vector <pii> q[maxn];
    ll ans[maxn],a[maxn],dep[maxn],st[maxn*4],add[maxn*4];
    int n,m,Q,id,l[maxn],r[maxn];
    
    void build(int o,int l,int r){
        if (l==r) st[o]=a[l];
        else {
            int m=l+((r-l)>>1);
            build(o<<1,l,m);
            build((o<<1)|1,m+1,r);
            st[o]=min(st[o<<1],st[(o<<1)|1]);
        }
    }
    
    void pushup(int o){
        st[o]=min(st[o<<1],st[o<<1|1]);
    }
    
    void pushdown(int o,int l,int r){
        if (add[o]){
            add[o<<1]+=add[o];
            add[o<<1|1]+=add[o];
            int m=l+((r-l)>>1);
            st[o<<1]+=add[o];
            st[o<<1|1]+=add[o];
            add[o]=0;
        }
    }
    
    void update(int o,int l,int r,int ql,int qr,ll addv){
        if (ql<=l&&qr>=r) {
            add[o]+=addv;
            st[o]+=addv;
            return;
        }
        pushdown(o,l,r);
        int m=l+((r-l)>>1);
        if (ql<=m) update(o<<1,l,m,ql,qr,addv);
        if (qr>=m+1) update(o<<1|1,m+1,r,ql,qr,addv);
        pushup(o);
    }
    
    ll query(int o,int l,int r,int ql,int qr){
        if(ql<=l&&qr>=r) return st[o];
        pushdown(o,l,r);
        int m=l+((r-l)>>1);
        ll ans=INF;
        if (ql<=m) ans=min(ans,query(o<<1,l,m,ql,qr));
        if (qr>=m+1) ans=min(ans,query(o<<1|1,m+1,r,ql,qr));
        return ans;
    }
    
    void dfs0(int u){
        ++id; assert(u==id);
        l[u]=id;
        if (!h[u].size()) a[u]=dep[u]; else a[u]=INF;
        for (int i=0;i<h[u].size();i++){
            int v=h[u][i].F;
            dep[v]=dep[u]+h[u][i].S;
            dfs0(v);
        }
        r[u]=id;
    }
    
    void dfs(int u){
        for (int i=0;i<q[u].size();i++) ans[q[u][i].F]=query(1,1,n,q[u][i].S.F,q[u][i].S.S)+dep[u];
        for (int i=0;i<h[u].size();i++){
            int v=h[u][i].F;
            update(1,1,n,l[v],r[v],-h[u][i].S*2);
            dfs(v);
            update(1,1,n,l[v],r[v],h[u][i].S*2);
        }
    }
    
    int main(){
        cin >> n >> Q;
        for (int i=2;i<=n;i++){
            ll u,v;
            scanf("%I64d%I64d",&u,&v);
            h[u].push_back((pi){i,v});
        }
        for (int i=1;i<=Q;i++){
            int u,v,w;
            scanf("%d%d%d",&w,&u,&v);
            q[w].push_back((pii){i,(pi){u,v}});
        }
        dfs0(1);
        build(1,1,n);
        dfs(1);
        for (int i=1;i<=Q;i++) printf("%I64d
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    Selenium系列(十五)
    Selenium系列(十四)
    Selenium系列(十三)
    Selenium系列(十二)
    Linux常用命令
    Linux
    Linux常用命令
    Linux常用命令
    Mysql常用sql语句(2)- 操作数据表
    Linux常用命令
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10357458.html
Copyright © 2020-2023  润新知