树剖例题

本文介绍了树剖分和线段树等高级数据结构的应用案例,包括国家集训队旅游问题、SDOI2015寻宝游戏及SDOI2016游戏等,展示了如何使用这些数据结构解决复杂的路径查询和更新问题。

P1505 [国家集训队]旅游

大裸题,第一次少打了个min。。。
错了无数次。。。
才发现少了个min
。。。。,也可以LCT

#include<cstdio>
#include<iostream>
#include<set>
using namespace std;
const int M=200010,INF=1000; 
int n,m,to[2*M],nex[M*2],head[M],vis[M],flag[M],coss[M],cap[M],caps[M],tot=1,val[M],f[M],cos[M*2],dep[M],top[M],cnt,size[M],ans,son[M],id[M];
struct xianduantree{
    int sum[4*M],minn[4*M],maxn[4*M],flag[4*M];
    void update(int x){
        sum[x]=(sum[x<<1]+sum[x<<1|1]);
        minn[x]=min(minn[x<<1],minn[x<<1|1]);
        maxn[x]=max(maxn[x<<1],maxn[x<<1|1]);
    }
    void built(int o,int l,int r){
        if(l==r) sum[o]=val[l],minn[o]=val[l],maxn[o]=val[l];
        else {
            int mid=(l+r)>>1;
            built(o<<1,l,mid);
            built(o<<1|1,mid+1,r);
            update(o);  
        }
    }
    void pushdown(int o){
        if(flag[o]==1) return ; 
        flag[o<<1]*=-1;flag[o<<1|1]*=-1;
        maxn[o<<1]*=-1;maxn[o<<1|1]*=-1;
        minn[o<<1]*=-1;minn[o<<1|1]*=-1;
        sum[o<<1|1]*=-1;sum[o<<1]*=-1;
        swap(minn[o<<1],maxn[o<<1]);
        swap(maxn[o<<1|1],minn[o<<1|1]);
        flag[o]=1;
    }
    void modify_1(int o,int l,int r,int id,int ins){

        if(l==r) {
            minn[o]=ins;maxn[o]=ins;
            sum[o]=ins;return ;
        }
        int mid=(l+r)>>1;
        pushdown(o);
        if(id<=mid)modify_1(o<<1,l,mid,id,ins);
        else modify_1(o<<1|1,mid+1,r,id,ins);
        update(o);
    }
    void modify_2(int o,int l,int r,int ql,int qr){
        if(l>qr||r<ql) return ;
        if(l>=ql&&r<=qr) {
            flag[o]*=-1;minn[o]*=-1;
            sum[o]*=-1;maxn[o]*=-1;swap(minn[o],maxn[o]);
            return ;
        } 
        int mid=(l+r)>>1;
        pushdown(o);
        modify_2(o<<1,l,mid,ql,qr);
        modify_2(o<<1|1,mid+1,r,ql,qr);
        update(o);
    }
    int query_sum(int o,int l,int r,int ql,int qr){
        if(l>qr||r<ql) return 0;
        if(l>=ql&&r<=qr) return sum[o];
        int mid=(l+r)>>1;
        pushdown(o);
        return (query_sum(o<<1,l,mid,ql,qr)+query_sum(o<<1|1,mid+1,r,ql,qr));
    }
    int query_min(int o,int l,int r,int ql,int qr){
        if(l>qr||r<ql) return INF;
        if(l>=ql&&r<=qr) return minn[o];
        int mid=(l+r)>>1;
        pushdown(o);
        return min(query_min(o<<1,l,mid,ql,qr),query_min(o<<1|1,mid+1,r,ql,qr));
    }
    int query_max(int o,int l,int r,int ql,int qr){
        if(l>qr||r<ql) return -INF;
        if(l>=ql&&r<=qr) return maxn[o];
        int mid=(l+r)>>1;
        pushdown(o);
        return max(query_max(o<<1,l,mid,ql,qr),query_max(o<<1|1,mid+1,r,ql,qr));
    }
}T;

void add(int x,int y,int z){
    nex[++tot]=head[x];cos[tot]=z;
    to[tot]=y;head[x]=tot;
}
int dfs1(int x){
    size[x]=1;dep[x]=dep[f[x]]+1;
    int maxsi=0;
    for(int i=head[x];i;i=nex[i]){
        int tmp=to[i];
        if(tmp!=f[x]){f[tmp]=x;
            int siz=dfs1(tmp);
            size[x]+=siz;
            if(maxsi<siz)
            son[x]=tmp,caps[x]=i/2,coss[x]=cos[i],maxsi=siz;
        }
    }
    return size[x];
}
void dfs2(int x,int topx,int z,int ww){
    top[x]=topx;
    id[x]=++cnt;cap[ww]=x;
    val[cnt]=z;
    if(!son[x]){return ;}
    dfs2(son[x],topx,coss[x],caps[x]);
    for(int i=head[x],tmp;i;i=nex[i])
    if(!id[tmp=to[i]])
    dfs2(tmp,tmp,cos[i],i/2);
}
void add_x(int x,int y){
    if(x==y) return ;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        T.modify_2(1,1,cnt,id[top[x]],id[x]);
        x=f[top[x]];
    }
    if(dep[x]<dep[y])swap(x,y);
    T.modify_2(1,1,cnt,id[y]+1,id[x]);
}
int sum_x(int x,int y){
    if(x==y) return  0;
    int ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=(ans+T.query_sum(1,1,cnt,id[top[x]],id[x]));
        x=f[top[x]];
    }
    if(dep[x]<dep[y])swap(x,y);
    ans=(ans+T.query_sum(1,1,cnt,id[y]+1,id[x]));
    return ans;
}
int min_x(int x,int y){
    if(x==y) return 0;
    int ans=INF;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=min(ans,T.query_min(1,1,cnt,id[top[x]],id[x]));
        x=f[top[x]];
    }
    if(dep[x]<dep[y])swap(x,y);
    ans=min(ans,T.query_min(1,1,cnt,id[y]+1,id[x]));
    return ans;
}
int max_x(int x,int y){
    if(x==y) return 0;
    int ans=-INF;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=max(ans,T.query_max(1,1,cnt,id[top[x]],id[x]));
        x=f[top[x]];
    }
    if(dep[x]<dep[y])swap(x,y);
    ans=max(ans,T.query_max(1,1,cnt,id[y]+1,id[x]));
    return ans;
}
int main(){scanf("%d",&n);
    for(int i=1;i<4*M;i++) T.flag[i]=1;
    for(int i=1,x,y,z;i<n;i++) scanf("%d%d%d",&x,&y,&z),x++,y++,add(x,y,z),add(y,x,z);
    dfs1(1);dfs2(1,1,0,n);T.built(1,1,cnt);T.minn[1]=INF,T.maxn[1]=-INF,T.sum[1]=0;
    scanf("%d",&m);
    while(m--){char s[20];int u,v;
        cin>>s;
        scanf("%d%d",&u,&v);u++,v++;
        if(s[0]=='S') printf("%d\n",sum_x(u,v));
        if(s[1]=='I') printf("%d\n",min_x(u,v));
        if(s[1]=='A') printf("%d\n",max_x(u,v));
        if(s[0]=='N') add_x(u,v);
        if(s[0]=='C') u--,v--,T.modify_1(1,1,cnt,id[cap[u]],v);
    }

}

[SDOI2015]寻宝游戏
树剖,用平衡树维护那个点有宝藏
然后找前驱和后继
发现删加边就是多了个与前驱后继的护理,如果正好在前驱后继的路上就不加

#include<cstdio>
#include<iostream>
#include<set>
#define int long long
using namespace std;
const int M=410000; 
int n,m,to[2*M],nex[M*2],head[M],vis[M],flag[M],pos[M],tot,f[M],cos[M],dep[M],top[M],cnt,size[M],ans,son[M],id[M],low[M],dis[M],LCA,LCA2;
void add(int x,int y,int z){
    nex[++tot]=head[x];cos[tot]=z;
    to[tot]=y;head[x]=tot;
}
int dfs1(int x){
    size[x]=1;dep[x]=dep[f[x]]+1;
    int maxsi=0;
    for(int i=head[x];i;i=nex[i]){
        int tmp=to[i];
        if(tmp!=f[x]){
            f[tmp]=x;dis[tmp]=dis[x]+cos[i];
            int siz=dfs1(tmp);
            size[x]+=siz;
            if(maxsi<siz)
            son[x]=tmp,maxsi=siz;
        }
    }
    return size[x];
}
void dfs2(int x,int topx){
    top[x]=topx;
    id[x]=++cnt;pos[cnt]=x;
    if(!son[x]){low[x]=cnt;return ;}
    dfs2(son[x],topx);
    for(int i=head[x],tmp;i;i=nex[i])
    if(!id[tmp=to[i]])
    dfs2(tmp,tmp);
    low[x]=cnt;
}
int lca(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        x=f[top[x]];
    } 
    return dep[x]>dep[y]?y:x;
}
set<int> s;
int dist(int x,int y){
    return dis[x]+dis[y]-2*dis[lca(x,y)];
}
int left(int x){
    if(s.empty())return x;
    set<int>::iterator it=s.lower_bound(id[x]);
    if(it==s.begin()) return pos[*(--s.end())];
    else return pos[*(--it)];
}
int right(int x){   
    if(s.empty())return x;
    set<int>::iterator it=s.upper_bound(id[x]);
    if(it==s.end()) return pos[*s.begin()];
    else return pos[*it];
}

int  main(){scanf("%lld%lld",&n,&m);
    for(int i=1,x,y,z;i<n;i++) scanf("%lld%lld%lld",&x,&y,&z),add(x,y,z),add(y,x,z);
    dfs1(1);dfs2(1,1);
    while(m--){int x,l,r;
        scanf("%lld",&x);
        if(flag[x]){
            s.erase(id[x]);
            l=right(x),r=left(x);
            ans-=dist(x,l)+dist(r,x)-dist(l,r);
        } else {
            s.insert(id[x]);
            l=right(x),r=left(x);
            ans+=dist(x,l)+dist(r,x)-dist(l,r);
        }
        flag[x]^=1;
        printf("%lld\n",ans); 
    }

}

P4069 [SDOI2016]游戏
树链剖分
用线段树维护
维护链头的值base,发现下面的值就是dist*k+base,找最大值用李超线段树维护这个一次函数
话说李超线段树还是不好打。。。

// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#define ll long long 
using namespace std;
const int M=1210000;const  ll INF=123456789123456789;
int n,m,to[2*M],nex[M*2],head[M],tot,f[M],dep[M],top[M],val[M],cnt,size[M],son[M],rank[M],id[M];
ll dis[M],cos[2*M];
struct node{
    ll k,b;int s;
    node(ll K=0,ll B=0,int S=0){k=K;b=B;s=S;}
    ll dist(int x){
        return (dis[x]-dis[s])*k+b;
    }

}; 
struct xianduantree{
    node val[M*4];ll minn[M];
    void build(int o,int l,int r){
        val[o]=(node){0,INF,0};
        minn[o]=INF;
        if(l>=r) return;
        int mid=(l+r)>>1;
        build((o<<1),l,mid),build((o<<1)|1,mid+1,r);

    }
    void insert(int o,int l,int r,node ins){
        ll ans=min(ins.dist(rank[l]),ins.dist(rank[r]));
        node tmp=val[o];
        if(l==r){
        if(ans<val[o].dist(rank[l])) val[o]=ins;minn[o]=min(minn[o],ans);return ;
        }int mid=(l+r)>>1;ans=min(ans,minn[o]);
        if(ins.k>tmp.k) swap(ins,tmp);
        if (ins.dist(rank[mid])<tmp.dist(rank[mid])){
            val[o]=ins,minn[o]=min(minn[o],ans);
            insert(o<<1,l,mid,tmp);
        }
        else{
            val[o]=tmp,minn[o]=min(minn[o],ans);
            insert(o<<1|1,mid+1,r,ins);
        }
    }
    void change(int o,int l,int r,int ql,int qr,node ins){

        if(l>=ql&&r<=qr) {
            insert(o,l,r,ins);return ;
        }
        int mid=(l+r)>>1;
        if(ql<=mid)change(o<<1,l,mid,ql,qr,ins);
        if(qr>mid) change(o<<1|1,mid+1,r,ql,qr,ins);
        minn[o]=min(minn[o],min(minn[o<<1],minn[o<<1|1]));
    } 
    ll ask(int o,int l,int r,int ql,int qr){
        int askl=max(ql,l),askr=min(r,qr);
        ll ans=min(val[o].dist(rank[askl]),val[o].dist(rank[askr]));
        if(ql<=l&&r<=qr) return min(ans,minn[o]);
        int mid=(l+r)>>1;
        if (ql<=mid) ans=min(ans,ask(o<<1,l,mid,ql,qr));
        if (qr>mid) ans=min(ans,ask(o<<1|1,mid+1,r,ql,qr));
        return ans;

    }
}T;
void add(int x,int y,ll z){
    to[++tot]=y;
    nex[tot]=head[x];
    cos[tot]=z;head[x]=tot;
}
int dfs1(int x){
    size[x]=1;dep[x]=dep[f[x]]+1;
    int maxsi=0;
    for(int i=head[x];i;i=nex[i]){
        int tmp=to[i];
        if(tmp!=f[x]){
            f[tmp]=x;dis[tmp]=dis[x]+cos[i];
            int siz=dfs1(tmp);
            size[x]+=siz;
            if(maxsi<siz)
            son[x]=tmp,maxsi=siz;
        }
    }
    return size[x];
}
void dfs2(int x,int topx){
    top[x]=topx;
    id[x]=++cnt;rank[cnt]=x;
    if(!son[x])return ;
    dfs2(son[x],topx);
    for(int i=head[x],tmp;i;i=nex[i])
    if(!id[tmp=to[i]])
    dfs2(tmp,tmp);
}
int lca(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        x=f[top[x]];
    } 
    return dep[x]>dep[y]?y:x;
}
void add_x(int x,int y,int a,int b){
    int LCA=lca(x,y),s=x,opt=1;ll base;node ins;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y),opt^=1;
        base=dis[top[x]]+dis[s]-2*dis[LCA];
        if(opt==1) base=dis[s]-dis[top[x]];
        base=a*base+b;
        ins=node(opt?-a:a,base,top[x]); 

        T.change(1,1,cnt,id[top[x]],id[x],ins);
        x=f[top[x]];
    }
    if(dep[x]<dep[y])swap(x,y),opt^=1;
    base=dis[x]+dis[s]-2*dis[LCA];
    if(opt==1) base=dis[s]-dis[x];
    base=a*base+b;
    ins=node(opt?-a:a,base,x);
    T.change(1,1,cnt,id[y],id[x],ins);
}
ll min_x(int x,int y){
    ll ans=INF;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=min(ans,T.ask(1,1,cnt,id[top[x]],id[x]));
        x=f[top[x]];
    }
    if(dep[x]<dep[y])swap(x,y);
    ans=min(ans,T.ask(1,1,cnt,id[y],id[x]));
    return ans;

}
int main(){
    scanf("%d%d",&n,&m);ll w;
    for(int i=1,x,y;i<n;i++) scanf("%d%d%lld",&x,&y,&w),add(x,y,w),add(y,x,w) ;
    dfs1(1);dfs2(1,1);

    T.build(1,1,cnt);
    while(m--){
        int opt,s,t,a,b;
        scanf("%d%d%d",&opt,&s,&t);
        if(opt==1) {
            scanf("%d%d",&a,&b);
            add_x(s,t,a,b);
        }
        if(opt==2) printf("%lld\n",min_x(s,t));

    }
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值