HDU 5333 Undirected Graph 离线 LCT维护最大生成树+树状数组

本文介绍了一种解决特定图论问题的方法,通过使用链接切割树(LCT)算法来高效处理一系列关于图的询问。具体地,针对给定的无向图,在不同区间内查询图中联通块的数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门【HDU 5333】
题意:一个无向图,m条边,Q个询问,每个询问查询若只保留图中的连接的两个点都在L,R之间的边,图包含多少个联通块。
思路:对询问以及边按照上届R为第一关键字从小到大排序,按照从小到大加边,用LCT维护边权为L的最大生成树,对于每个询问,查询L在[L,R]区间的边的个数,联通块的数量就是n-边数。
代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int INF =1e8;
const int maxn=300010;
namespace BIT{
    int data[maxn];
    int n;
    void init(int _n){
        memset(data,0,sizeof(data));
        n=_n;
    }
    int lowbit(int x){
        return x&(-x);
    }
    void add(int pos,int val){
        while(pos<=n){
            data[pos]+=val;
            pos+=lowbit(pos);
        }
    }
    int sum(int pos){
        int ret=0;
        while(pos){
            ret+=data[pos];
            pos-=lowbit(pos);
        }
        return ret;
    }

}

namespace link_cut_tree{
    #define NIL POOL
    const int max_n =330010;
    struct Node{
        int val,pos,mpos;
        int l,r;
        bool rev,root;
        Node *lch,*rch,*fa;
        Node (){
            root=rev=false;
            mpos=pos=0;
        }
        Node (int _val,int _pos,Node *_lch,Node *_rch,Node *_fa)
        :val(_val),pos(_pos),lch(_lch),rch(_rch),fa(_fa){
            root=true;
            mpos=pos;
            rev=false;
        }
    }POOL[maxn],*pool[maxn];
    struct LCT{
        Node *node[max_n],*stk[maxn];
        LCT(){}
        int tot;
        int tp;
        int min1(int a,int b){
            if(node[a]->val<node[b]->val)return a;
            return b;
        }
        void init(){
            tot=0;
            for(int i=1;i<maxn;i++)pool[tot++]=POOL+i;
            new(NIL)Node;
            NIL->lch=NIL->rch=NIL->fa=NIL;
            node[0]=new(pool[--tot])Node(INF,0,NIL,NIL,NIL);
        }
        void build(int n){
            tp=n;
            for(int i=1;i<=n;i++){
                node[i]=new(pool[--tot])Node(0,0,NIL,NIL,NIL);
            }
        }
        void update(Node *t){
            if(t==NIL)return;
            t->mpos=min1(t->pos,min1(t->lch->mpos,t->rch->mpos));
        }
        void reverse(Node *t){
            if(t==NIL)return;
            t->rev^=1;
            swap(t->lch,t->rch);
        }
        void pushdown(Node *t){
            if(t==NIL)return;
            if(t->rev){
                reverse(t->lch);
                reverse(t->rch);
                t->rev^=1;
            }
        }
        void zig(Node *t){
            Node *f=t->fa,*c=t->rch;
            if(f->root)t->root=true,f->root=false;
            else (f->fa->lch==f?f->fa->lch:f->fa->rch)=t;
            t->fa=f->fa,t->rch=f,f->lch=c,f->fa=t,c->fa=f;
            update(f);
        }
        void zag(Node *t){
            Node *f=t->fa,*c=t->lch;
            if(f->root)t->root=true,f->root=false;
            else (f->fa->lch==f?f->fa->lch:f->fa->rch)=t;
            t->fa=f->fa,t->lch=f,f->rch=c,f->fa=t,c->fa=f;
            update(f);
        }
        void splay(Node *t){
            Node *p=t;
            int top=0;
            stk[top]=t;
            while(!p->root){
                stk[++top]=p->fa;
                p=p->fa;
            }
            while(top>=0){
                pushdown(stk[top--]);
            }
            while(!t->root){
                if(t->fa->root){
                    if(t->fa->lch==t)zig(t);
                    else zag(t);
                }
                else {
                    if(t->fa->fa->lch==t->fa){
                        if(t->fa->lch==t)zig(t->fa),zig(t);
                        else zag(t),zig(t);
                    }
                    else {
                        if(t->fa->lch==t)zig(t),zag(t);
                        else zag(t->fa),zag(t);
                    }
                }
            }
            update(t);
        }
        Node * expose(Node *t){
            Node *p=t,*q=NIL;
            while(p!=NIL){
                splay(p);
                p->rch->root=true;
                p->rch=q;
                p->rch->root=false;
                update(p);
                q=p;
                p=p->fa;
            }
            return q;
        }
        void evert(Node *t){
            t=expose(t);
            reverse(t);
        }
        void cut(int a,int b){
            evert(node[b]);
            expose(node[a]);
            splay(node[a]);
            node[a]->lch->fa=NIL;
            node[a]->lch->root=true;
            node[a]->lch=NIL;
            expose(node[b]);
        }
        void link(int a,int b){
            evert(node[b]);
            splay(node[b]);
            node[b]->fa=node[a];
            expose(node[b]);
        }
        void Link(int a,int b,int val){
            node[++tp]=new(pool[--tot])Node(val,tp,NIL,NIL,NIL);
            node[tp]->l=a;
            node[tp]->r=b;
            link(a,tp);
            link(tp,b);
            BIT::add(val,1);
        }
        int querry(int a,int b){
            if(getroot(node[b])!=getroot(node[a]))return -1;
            Node *p=node[b],*q=NIL;
            expose(node[a]);
            int ret;
            while(p!=NIL){
                splay(p);
                if(p->fa==NIL){
                    ret=min1(p->pos,min1(p->rch->mpos,q->mpos));
                }
                p->rch->root=true;
                p->rch=q;
                p->rch->root=false;
                update(p);
                q=p;
                p=p->fa;
            }
            return ret;
        }
        void erase(int a){
            BIT::add(node[a]->val,-1);
            cut(node[a]->l,a);
            cut(node[a]->r,a);
            pool[tot++]=node[a];
        }
        Node* getroot(Node *t){
            t=expose(t);
            while(1){
                if(t->lch!=NIL) t=t->lch;
                else return t;
            }
        }

    };
}
link_cut_tree::LCT T;

struct Querry{
    int kind,ans,l,r,id;
    Querry(){}
    Querry(int _k,int _l,int _r,int _id)
    :kind(_k),l(_l),r(_r),id(_id){
        if(l>r)swap(l,r);
    }
    bool operator<(const Querry  & a)const{
        if(r==a.r){
            if(kind==a.kind){
                return l<a.l;
            }
            return kind<a.kind;
        }
        return r<a.r;
    }
}Q[maxn];
bool cmp(const Querry & a,const Querry & b){
    if(a.kind==b.kind)return a.id<b.id;
    return a.kind>b.kind;
}
void read(int &a){
    char c;
    while(c=getchar(),c<'0'||c>'9');
    a=c-'0';
    while(c=getchar(),c>='0'&&c<='9')
        a=a*10+c-'0';
}
int main(){
    int n,m,q;
//    freopen("1007.in","r",stdin);
//    freopen("data.out","w",stdout);
    while(~scanf("%d%d%d",&n,&m,&q)){
        T.init();
        T.build(n);
        BIT::init(n);
        int a,b,tot=0;
        for(int i=0;i<m;i++){
                read(a),read(b);
//            scanf("%d%d",&a,&b);
            Q[tot++]=Querry(0,a,b,i);
        }
        for(int i=0;i<q;i++){
                read(a),read(b);
//            scanf("%d%d",&a,&b);
            Q[tot++]=Querry(1,a,b,i);
        }
        sort(Q,Q+tot);
        for(int i=0;i<tot;i++){
            if(Q[i].kind==0){
                int tp=T.querry(Q[i].l,Q[i].r);
                if(tp==-1){
                    T.Link(Q[i].r,Q[i].l,Q[i].l);
                    continue;
                }
                if(T.node[tp]->val>=Q[i].l)continue;
                T.erase(tp);
                T.Link(Q[i].r,Q[i].l,Q[i].l);
            }
            else {
                Q[i].ans=BIT::sum(Q[i].r)-BIT::sum(Q[i].l-1);
            }
        }
        sort(Q,Q+tot,cmp);
        for(int i=0;i<q;i++){
            printf("%d\n",n-Q[i].ans);
        }
    }
    return 0;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值