其他分享
首页 > 其他分享> > P1967 货车运输

P1967 货车运输

作者:互联网

容易发现此题中需要找到尽可能大的边来走?

那么我们求一棵最大生成树,把必要的边保留下来就行了。

之后要求两点间的最小边权?

你可以选择倍增,可以选择树剖,但我选择拉LCTLCTLCT的板子…(指针警告&封装警告&STL画风警告)

似乎理论复杂度优秀但常数巨大???(1000+ms without O2)

所以简单讲一下做法

KruskalKruskalKruskal求最大生成树的时候把选中的边在LCTLCTLCT上连起来就行了。

由于LCTLCTLCT存的是点权,而此题要求边权,那么把边都建成点就好了。。。

然后原图中的点权要设为无穷大以防影响答案。。。

由于我的LCTLCTLCT高度封装,所以每次拉板子只要做很小的改动即可

所以这个题解的亮点也在板子吧

然而我的板子也因此很长,为了防止影响阅读体验,先放主要代码再放板子。

算法主要代码,暂时不想学LCTLCTLCT的看这一段就行了。还不行就当伪代码看吧

template<typename Argument_type,typename Result_type>//板子要用仿函数来实现运算
//这个写法STL也需要,口以康康
class Min
{
    public:
        Result_type operator()(const Argument_type& x,const Argument_type& y)const
        {
            return std::min(x,y);
        }
};

template<typename T>
void read(T& x)
{
    bool f=0;
    x=0;
    char c=std::getchar();
    while(c<'0'||c>'9')f|=(c=='-'),c=getchar();
    while(c>='0'&&c<='9')x=x*10+(c^48),c=getchar();
}

template<typename T>
void write(T x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>=10)write(x/10);
    putchar(x%10^48);
}

const int N=100005,M=500005;

int n,m,fa[N];
int find(int x)
{
    if(x==fa[x])return x;
    return fa[x]=find(fa[x]);
}

struct Edge
{
    int from,to,w;
    bool operator<(const Edge& rhs)const
    {
        return w<rhs.w;
    }
};
Edge E[M];
bool cmp(const Edge& a,const Edge& b)
{
    return b<a;
}

link_cut_tree<int,Min<int,int> > my_LCT;
link_cut_tree<int,Min<int,int> >::iterator iters[N];//迭代器指向原图中的点在LCT中的对应点

void kruskal()
{
    std::sort(E,E+m,cmp);
    for(int i=0;i<m;++i)
    {
        int u=E[i].from,v=E[i].to;
        int fu=find(u),fv=find(v);
        if(fu==fv)continue;
        fa[fu]=fv;
        link_cut_tree<int,Min<int,int> >::iterator it=my_LCT.make_node(E[i].w);
        my_LCT.link(iters[u],it);
        my_LCT.link(it,iters[v]);
    }
}

int main()
{
    read(n);
    read(m);
    for(int i=1;i<=n;++i)
    {
        iters[i]=my_LCT.make_node(0x7fffffff);
        fa[i]=i;
    }
    for(int i=0;i<m;++i)
    {
        read(E[i].from);
        read(E[i].to);
        read(E[i].w);
    }
    kruskal();
    int q;
    read(q);
    while(q--)
    {
        int u,v;
        read(u),read(v);
        std::pair<bool,int> res=my_LCT.query(iters[u],iters[v]);//为了判不连通的情况,查询返回的是pair,第一项表示是否连通
        write(res.first?res.second:-1);
        putchar('\n');
    }
}

LCTLCTLCT板子,难打但便于复制和重用,喜欢拿去,看不懂的话我博客里有一篇专门讲LCTLCTLCT的可以康康。

平时做题用用算了,考试打这个是作死

#include<cstdio>
#include<iostream>
#include<algorithm>

//#define MEMPOOL //内存池开关,去掉注释就可以用内存池,但实测效果不佳

template<typename Value_type,typename Functor>
class LCT_splay
{
    public:
        struct Node;
        Node* __new_node(const Value_type&);
#ifdef MEMPOOL
    private:
        Node mem_pool[1<<20];
        int tot;
#endif
};
template<typename Value_type,typename Functor>
struct LCT_splay<Value_type,Functor>::Node:Functor
{
    Value_type val,sum;
    Node* ftr;
    Node* ch[2];
//    Node*& lc;
//    Node*& rc;
    #define lc ch[0]//省空间写法
    #define rc ch[1]
    bool rev;

    Node(const Value_type& v=Value_type()):
        val(v),
        sum(v),
        ftr(NULL),
//        lc(ch[0]),
//        rc(ch[1]),
        rev(0) {ch[0]=ch[1]=NULL;}

    void reverse();
    void push_down();
    void push_all();
    void maintain();
    bool is_root();
    void rotate();
    void splay();
};

template<typename Value_type,typename Functor>
void LCT_splay<Value_type,Functor>::Node::reverse()
{
    rev^=1;
}

template<typename Value_type,typename Functor>
void LCT_splay<Value_type,Functor>::Node::push_down()
{
    if(!rev)return;
    rev=0;
    Node* ptr=lc;
    lc=rc;
    rc=ptr;
    if(lc!=NULL)lc->reverse();
    if(rc!=NULL)rc->reverse();
}

template<typename Value_type,typename Functor>
void LCT_splay<Value_type,Functor>::Node::push_all()
{
    if(!is_root())this->ftr->push_all();
    push_down();
}

template<typename Value_type,typename Functor>
void LCT_splay<Value_type,Functor>::Node::maintain()
{
    sum=val;
    if(lc!=NULL)sum=Functor::operator()(lc->sum,sum);
    if(rc!=NULL)sum=Functor::operator()(sum,rc->sum);
}

template<typename Value_type,typename Functor>
bool LCT_splay<Value_type,Functor>::Node::is_root()
{
    return ftr==NULL||(ftr->lc!=this&&ftr->rc!=this);
}

template<typename Value_type,typename Functor>
void LCT_splay<Value_type,Functor>::Node::rotate()
{
    Node *nftr=ftr,*gftr=ftr->ftr;
    bool is_rc=nftr->rc==this;
    bool is_rf=gftr!=NULL?gftr->rc==nftr:0;
    ftr=gftr;
    if(!nftr->is_root())gftr->ch[is_rf]=this;
    nftr->ch[is_rc]=this->ch[!is_rc];
    if(this->ch[!is_rc]!=NULL)this->ch[!is_rc]->ftr=nftr;
    nftr->ftr=this;
    this->ch[!is_rc]=nftr;
    nftr->maintain();
    maintain();
}

template<typename Value_type,typename Functor>
void LCT_splay<Value_type,Functor>::Node::splay()
{
    push_all();
    while(!is_root())
    {
        Node *nftr=ftr,*gftr=ftr->ftr;
        if(nftr->is_root())rotate();
        else
        {
            if((gftr->lc==nftr)^(nftr->lc==this))rotate();
            else nftr->rotate();
            rotate();
        }
    }
}

template<typename Value_type,typename Functor>
typename
LCT_splay<Value_type,Functor>::Node* LCT_splay<Value_type,Functor>::__new_node(const Value_type& v)
{
#ifdef MEMPOOL
    if(tot==1<<20)
    {
        fprintf(stderr,"Error:No enough memory\n");
        return NULL;
    }
    mem_pool[tot++].val=v;
    return mem_pool+tot-1;
#else
    return new Node(v);
#endif
}



template<typename Value_type,typename Functor>
class link_cut_tree:public LCT_splay<Value_type,Functor>
{
    typedef typename LCT_splay<Value_type,Functor>::Node Node;
    private:
        void access(Node*);
        void make_root(Node*);
        Node* find_root(Node*);
        bool split(Node*,Node*);
    public:
        struct iterator;
        iterator make_node(const Value_type&);
        bool link(const iterator&,const iterator&);
        bool cut(const iterator&,const iterator&);
        std::pair<bool,Value_type> query(iterator,iterator);
        bool modify(iterator,const Value_type&);
};

template<typename Value_type,typename Functor>
struct link_cut_tree<Value_type,Functor>::iterator
{
    private:
        Node* ptr;
        friend class link_cut_tree;
    public:
        Value_type operator*()const{return ptr->val;}
        iterator(Node* p=NULL):ptr(p) {}
        iterator(const iterator& iter):ptr(iter.ptr) {}
};

template<typename Value_type,typename Functor>
void link_cut_tree<Value_type,Functor>::access(Node* ptr)
{
    for(Node* nptr=NULL;ptr!=NULL;nptr=ptr,ptr=ptr->ftr)
        {
            ptr->splay();
            ptr->rc=nptr;
            ptr->maintain();
        }
}

template<typename Value_type,typename Functor>
void link_cut_tree<Value_type,Functor>::make_root(Node* ptr)
{
    access(ptr);
    ptr->splay();
    ptr->reverse();
}

template<typename Value_type,typename Functor>
typename
link_cut_tree<Value_type,Functor>::Node* link_cut_tree<Value_type,Functor>::find_root(Node* ptr)
{
    access(ptr);
    ptr->splay();
    while(ptr->lc!=NULL)ptr->push_down(),ptr=ptr->lc;
    ptr->splay();
    return ptr;
}

template<typename Value_type,typename Functor>
bool link_cut_tree<Value_type,Functor>::split(Node* sptr,Node* eptr)
{
    make_root(sptr);
    if(find_root(eptr)!=sptr)return 0;
    eptr->splay();
    return 1;
}

template<typename Value_type,typename Functor>
typename
link_cut_tree<Value_type,Functor>::iterator link_cut_tree<Value_type,Functor>::make_node(const Value_type& v)
{
    return iterator(LCT_splay<Value_type,Functor>::__new_node(v));
}

template<typename Value_type,typename Functor>
bool link_cut_tree<Value_type,Functor>::link(const iterator& siter,const iterator& eiter)
{
    Node* sptr=siter.ptr;
    Node* eptr=eiter.ptr;
    make_root(sptr);
    if(find_root(eptr)==sptr)return 0;
    sptr->ftr=eptr;
    return 1;
}

template<typename Value_type,typename Functor>
bool link_cut_tree<Value_type,Functor>::cut(const iterator& siter,const iterator& eiter)
{
    Node* sptr=siter.ptr;
    Node* eptr=eiter.ptr;
    make_root(sptr);
    if(find_root(eptr)!=sptr||eptr->ftr!=sptr||eptr->lc!=NULL)return 0;
    eptr->ftr=NULL;
    sptr->lc=NULL;
    sptr->maintain();
    return 1;
}

template<typename Value_type,typename Functor>
std::pair<bool,Value_type> link_cut_tree<Value_type,Functor>::query(iterator siter,iterator eiter)
{
    Node* sptr=siter.ptr;
    Node* eptr=eiter.ptr;
    if(!split(sptr,eptr))return std::make_pair(0,Value_type());
    return std::make_pair(1,eptr->sum);
}

template<typename Value_type,typename Functor>
bool link_cut_tree<Value_type,Functor>::modify(iterator iter,const Value_type& v)
{
    Node* ptr=iter.ptr;
    if(ptr==NULL)return 0;
    ptr->splay();
    ptr->val=v;
    ptr->maintain();
    return 1;
}
#undef lc
#undef rc

开始用了自己考场上打的LCTLCTLCT结果各种WAWAWA和RERERE,最后还是懒癌发作拖了板子。。。

最后要说几句:

LCT大法好!

指针大法好!

封装大法好!

end.

标签:Node,const,iterator,货车运输,splay,template,P1967,ptr
来源: https://blog.csdn.net/qq_42722211/article/details/96424992