树上并查集

题目链接:传送门

题意:
给你一个图,有q次操作,对于每次操作:opt=1,则修改相应的边。opt=2,则求解给定区间的边所构成的最小生成树。
代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e2+5;
struct node{
    int x,y,val;
}edge[30005];
struct treeNode{
    int l,r,pos;
    bool operator<(const treeNode &rs)const{
        return edge[pos].val>edge[rs.pos].val;
    }
}tree[30005<<2];
int n,m,quNum,ans,fa[maxn];
void init(int upper){
    for (int i=1;i<=upper;i++)fa[i]=i;
}
int _find(int x){
    if(fa[x]==x)return x;
    return fa[x]=_find(fa[x]);
}
void Merge(int x,int y){
    fa[x]=y;
}
void pushUp(int id){
    int lPos,rPos;
    lPos=tree[id<<1].pos;
    rPos=tree[id<<1|1].pos;
    if(edge[lPos].val<=edge[rPos].val)tree[id].pos=lPos;
    else tree[id].pos=rPos;
}
void build(int l,int r,int id){
     tree[id].l=l,tree[id].r=r;
     if(l==r){
        tree[id].pos=l;
        return;
     }
     int mid=(l+r)>>1;
     build(l,mid,id<<1);
     build(mid+1,r,id<<1|1);
     pushUp(id);
}
void update(int id,int pos){
     if(tree[id].l==tree[id].r)return;
     int mid=(tree[id].l+tree[id].r)>>1;
     if(pos<=mid)update(id<<1,pos);
     else update(id<<1|1,pos);
     pushUp(id);
}
int query(int id,int l,int r){
    if(l<=tree[id].l&&tree[id].r<=r)return tree[id].pos;
    if(tree[id].l==tree[id].r)return tree[id].pos;
    int mid=(tree[id].l+tree[id].r)>>1;
    if(r<=mid)return query(id<<1,l,r);
    else if(l>mid)return query(id<<1|1,l,r);
    else{
        int id1,id2,minn;
        id1=query(id<<1,l,r);
        id2=query(id<<1|1,l,r);
        minn=id2;
        if(edge[id1].val<=edge[id2].val)minn=id1;
        return minn;
    }
}
int main(){
    int i,op,l,r,pos,fx,fy,cnt,id1;
    treeNode now;
    while(scanf("%d%d%d",&n,&m,&quNum)!=EOF){
         ans=0;priority_queue<treeNode>qu;
         for (i=1;i<=m;i++)scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].val);
         build(1,m,1);
         while(quNum--){
            scanf("%d",&op);
            if(op==1){
               scanf("%d",&pos);
               scanf("%d%d%d",&edge[pos].x,&edge[pos].y,&edge[pos].val);
               update(1,pos);
            }
            else{
                scanf("%d%d",&l,&r);
                if(r-l+1<n-1){
                    printf("Impossible\n");continue;
                }
                init(n),cnt=n;ans=0;
                id1=query(1,l,r);
                qu.push({l,r,id1});
                while(!qu.empty()){
                    now=qu.top();qu.pop();
                    fx=_find(edge[now.pos].x);fy=_find(edge[now.pos].y);
                    if(fx!=fy)Merge(fx,fy),cnt--,ans+=edge[now.pos].val;
                    if(now.l<=now.pos-1)id1=query(1,now.l,now.pos-1),qu.push({now.l,now.pos-1,id1});///,printf("new l=%d,r=%d minEdgeId=%d\n",now.l,now.pos-1,id1);
                    if(now.pos+1<=now.r)id1=query(1,now.pos+1,now.r),qu.push({now.pos+1,now.r,id1});///,printf("new l=%d,r=%d minEdgeId=%d\n",now.pos+1,now.r,id1);
                    if(cnt==1)break;
                }
                if(cnt!=1)printf("Impossible\n");
                else printf("%d\n",ans);
                while(!qu.empty())qu.pop();
            }
         }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值