【bzoj 5216】公路建設(線段樹+Kruskal)

傳送門biu~
用線段樹維護使用編號在[l,r]內的道路最終會選擇哪些道路。即線段樹每個節點記錄一個邊的集合,集合大小顯然不超過n。
在合併兩個區間的時候採用Kruskal用歸併的方式合併(暴力)。

#include<bits/stdc++.h>
#define N 105
#define M 100005
#define inf 0x3f3f3f3f
using namespace std;
struct Node{int l,r,an[N];}tree[M<<2];
struct Edge{int u,v,w;}e[M];
int n,m,T,fa[N],ans[N][N],cnt;
int search(int x){return fa[x]==x ? x : fa[x]=search(fa[x]);}
inline void Update(int re[],int x[],int y[]){
    int now=0,lx=1,ly=1;
    for(int i=1;i<=n;++i)   fa[i]=i;
    while(now<n && (x[lx] || y[ly])){
        if(x[lx] && e[x[lx]].w<=e[y[ly]].w){
            int fv=search(e[x[lx]].v),fu=search(e[x[lx]].u);
            if(fv^fu)   fa[fv]=fu,re[++now]=x[lx];
            ++lx;
        }
        else if(y[ly] && e[y[ly]].w<=e[x[lx]].w){
            int fv=search(e[y[ly]].v),fu=search(e[y[ly]].u);
            if(fv^fu)   fa[fv]=fu,re[++now]=y[ly];
            ++ly;
        }
    }
    while(now<n &&  re[now])    re[++now]=0;
}
void build(int num,int l,int r){
    tree[num].l=l,tree[num].r=r;
    if(l==r){
        tree[num].an[1]=r;
        return;
    }
    int mid=l+r>>1;
    build(num<<1,l,mid),build(num<<1|1,mid+1,r);
    Update(tree[num].an,tree[num<<1].an,tree[num<<1|1].an);
}
void Query(int num,int l,int r,int now){
    if(l==tree[num].l && r==tree[num].r){
        for(int i=1;i<n;++i)    ans[now][i]=tree[num].an[i];
        return;
    }
    int mid=tree[num].l+tree[num].r>>1,ls,rs;
    if(mid>=r){
        Query(num<<1,l,r,ls=++cnt);
        for(int i=1;i<n;++i)    ans[now][i]=ans[ls][i];
    }
    else if(mid<l){
        Query(num<<1|1,l,r,rs=++cnt);
        for(int i=1;i<n;++i)    ans[now][i]=ans[rs][i];
    }
    else{
        Query(num<<1,l,mid,ls=++cnt),Query(num<<1|1,mid+1,r,rs=++cnt);
        Update(ans[now],ans[ls],ans[rs]);
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&T);
    for(int i=1;i<=m;++i)   scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    e[0].w=inf; build(1,1,m);
    while(T--){
        int l,r,Ans=0;
        scanf("%d%d",&l,&r);
        Query(1,l,r,cnt=1);
        for(int i=1;ans[1][i];++i)      Ans+=e[ans[1][i]].w;
        printf("%d\n",Ans);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章