zoukankan      html  css  js  c++  java
  • 【BZOJ3669】[Noi2014]魔法森林 LCT

      终于不是裸的LCT了。。。然而一开始一眼看上去这是kruskal。。不对,题目要求1->n的路径上的每个点的两个最大权值和最小,这样便可以用LCT来维护一个最小生成路(瞎编的。。。),先以a为关键字排序,然后加边,所以每次加入一条边时a一定是最大的,考虑b的大小,当形成环时,考虑用当前边替换掉环内b最大的边,当然是当前边b小于权值最大的边拉!

      Tips:1.注意LCT要把每条边也作为一个节点,方便连接,然后每个节点维护所在边在边集里的编号即可。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <algorithm>
      4 #define N 50050
      5 #define M 100100
      6 #define inf 0x7fffffff
      7 using namespace std;
      8 int n,m,ans; 
      9 struct E{int x,y,a,b;}e[M];
     10 struct node
     11 {
     12     node *fa,*ch[2];
     13     void init();
     14     int pos,rpos;
     15     bool rev;
     16     bool chr() {return this==fa->ch[1];}
     17     bool isrt() {return this!=fa->ch[1] && this!=fa->ch[0];}
     18     void setc(node *x,int t) {this->ch[t]=x; x->fa=this;}
     19     void push_up();
     20     void push_down();
     21 /*    void push_down()
     22     {
     23         if (this==null) return;
     24         if (!x->isrt()) x->fa->push_down();
     25         if (rev)
     26         {
     27             ch[1]->rev^=1;
     28             ch[0]->rev^=1;
     29             swap(ch[1],ch[0]);
     30             rev=0;
     31         }
     32     }
     33     void push_up()
     34     {
     35         if (this==null) return;
     36         pos=rpos;
     37         if (ch[0]!=null && e[pos].b<e[ch[0]->pos].b)    pos=ch[0]->pos;
     38         if (ch[1]!=null && e[pos].b<e[ch[1]->pos].b)    pos=ch[1]->pos;
     39     }*/
     40 }pool[N+M],*pt=pool,*point[N],*et[M],*null;
     41 void node::init() {ch[0]=ch[1]=fa=null; pos=0; rev=0; rpos=0;}
     42 void node::push_up()
     43 {
     44     if (this==null) return;
     45     pos=rpos;
     46     if (ch[0]!=null && e[pos].b<e[ch[0]->pos].b)    pos=ch[0]->pos;
     47     if (ch[1]!=null && e[pos].b<e[ch[1]->pos].b)    pos=ch[1]->pos;
     48 } 
     49 void node::push_down()
     50 {
     51     if (this==null) return;
     52         if (!this->isrt()) this->fa->push_down();
     53         if (rev)
     54         {
     55             if (ch[1]!=null) ch[1]->rev^=1;
     56             if (ch[0]!=null) ch[0]->rev^=1;
     57             swap(ch[1],ch[0]);
     58             rev=0;
     59         }
     60 }
     61 namespace LCT
     62 {
     63     node *NewNode()
     64     {
     65         pt++;
     66         pt->init();
     67         return pt;
     68     }
     69     void rotate(node *x)
     70     {
     71         node *r=x->fa;
     72         if (x==null || r==null) return;
     73         int t=x->chr();
     74         if (r->isrt()) x->fa=r->fa;
     75         else r->fa->setc(x,r->chr());
     76         r->setc(x->ch[t^1],t);
     77         x->setc(r,!t);
     78         x->push_up(); r->push_up();
     79     }
     80     void Splay(node *x)
     81     {
     82         x->push_down();
     83         for (;!x->isrt();rotate(x))
     84             if (!x->fa->isrt())
     85                 if (x->chr()==x->fa->chr()) rotate(x->fa);
     86                 else rotate(x);
     87         x->push_up();
     88     }
     89     void Access(node *x)
     90     {
     91         node *r=null;
     92         for (;x!=null;r=x,x=x->fa)
     93         {
     94             Splay(x);
     95             x->ch[1]=r;
     96         }
     97     }
     98     void MoveRoot(node *x)
     99     {
    100         Access(x);
    101         Splay(x);
    102         x->rev^=1;
    103     }
    104     void Link(node *x,node *y)
    105     {
    106         MoveRoot(x);
    107         x->fa=y;
    108     }
    109     void Cut(node *x,node *y)
    110     {
    111         MoveRoot(x);
    112         Access(y); Splay(y);
    113         y->ch[0]->fa=null; y->ch[0]=null;
    114     }
    115     node *Find(node *x)
    116     {
    117         Access(x);
    118         Splay(x);
    119         while (x->ch[0]!=null) x=x->ch[0];
    120         return x;
    121     }
    122     int Query(node *x,node *y)
    123     {
    124         MoveRoot(x);
    125         Access(y);Splay(y);
    126         return y->pos;
    127     }
    128 }
    129 inline int read()
    130 {
    131     char c;
    132     int ans=0,f=1;
    133     while (!isdigit(c=getchar())) if (c=='-') f=-1;
    134     ans=c-'0';
    135     while (isdigit(c=getchar())) ans=ans*10+c-'0';
    136     return ans*f;
    137 }
    138 inline bool cmp (E a,E b) {return a.a<b.a;}
    139 using namespace LCT;
    140 int main()
    141 {
    142     n=read();m=read();
    143     null=pt++;
    144     null->init();
    145     for (int i=1;i<=m;i++) {e[i].x=read(); e[i].y=read(); e[i].a=read(); e[i].b=read();}
    146     for (int i=1;i<=n;i++)     point[i]=NewNode();
    147     sort(e+1,e+m+1,cmp);
    148     ans=inf;e[0].b=-inf;
    149     for (int i=1;i<=m;i++)
    150     {
    151         int x=e[i].x,y=e[i].y,b=e[i].b;
    152         et[i]=NewNode(); et[i]->pos=et[i]->rpos=i;
    153         if (Find(point[x])==Find(point[y]))
    154         {
    155             int pos=Query(point[x],point[y]);
    156             if (e[pos].b>b)
    157             {
    158                 Cut(et[pos],point[e[pos].x]);
    159                 Cut(et[pos],point[e[pos].y]);
    160                 Link(et[i],point[x]);
    161                 Link(et[i],point[y]);
    162             }
    163         }
    164         else 
    165         {
    166             Link(et[i],point[x]);
    167             Link(et[i],point[y]);
    168         }
    169         if (Find(point[1])==Find(point[n])) ans=min(ans,e[i].a+e[Query(point[1],point[n])].b);
    170     }
    171     if (ans!=inf) printf("%d
    ",ans);
    172     else printf("-1
    ");
    173     return 0; 
    174 }
    View Code

    Description

    为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士。魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M。初始时小E同学在号节点1,隐士则住在号节点N。小E需要通过这一片魔法森林,才能够拜访到隐士。

    魔法森林中居住了一些妖怪。每当有人经过一条边的时候,这条边上的妖怪就会对其发起攻击。幸运的是,在号节点住着两种守护精灵:A型守护精灵与B型守护精灵。小E可以借助它们的力量,达到自己的目的。

    只要小E带上足够多的守护精灵,妖怪们就不会发起攻击了。具体来说,无向图中的每一条边Ei包含两个权值Ai与Bi。若身上携带的A型守护精灵个数不少于Ai,且B型守护精灵个数不少于Bi,这条边上的妖怪就不会对通过这条边的人发起攻击。当且仅当通过这片魔法森林的过程中没有任意一条边的妖怪向小E发起攻击,他才能成功找到隐士。

    由于携带守护精灵是一件非常麻烦的事,小E想要知道,要能够成功拜访到隐士,最少需要携带守护精灵的总个数。守护精灵的总个数为A型守护精灵的个数与B型守护精灵的个数之和。

    Input

    第1行包含两个整数N,M,表示无向图共有N个节点,M条边。 接下来M行,第行包含4个正整数Xi,Yi,Ai,Bi,描述第i条无向边。其中Xi与Yi为该边两个端点的标号,Ai与Bi的含义如题所述。 注意数据中可能包含重边与自环。

    Output

    输出一行一个整数:如果小E可以成功拜访到隐士,输出小E最少需要携带的守护精灵的总个数;如果无论如何小E都无法拜访到隐士,输出“-1”(不含引号)。

    Sample Input

    【输入样例1】
    4 5
    1 2 19 1
    2 3 8 12
    2 4 12 15
    1 3 17 8
    3 4 1 17





    【输入样例2】


    3 1
    1 2 1 1



    Sample Output

    【输出样例1】

    32
    【样例说明1】
    如果小E走路径1→2→4,需要携带19+15=34个守护精灵;
    如果小E走路径1→3→4,需要携带17+17=34个守护精灵;
    如果小E走路径1→2→3→4,需要携带19+17=36个守护精灵;
    如果小E走路径1→3→2→4,需要携带17+15=32个守护精灵。
    综上所述,小E最少需要携带32个守护精灵。



    【输出样例2】


    -1
    【样例说明2】
    小E无法从1号节点到达3号节点,故输出-1。

    HINT

    2<=n<=50,000


    0<=m<=100,000




    1<=ai ,bi<=50,000

    Source

    —Anime Otaku Save The World.
  • 相关阅读:
    tf.keras 用生成器读取图片数据+预处理
    pandas时间序列操作
    jupyter notebook 字体美化
    python响应式的数据可视化工具Dash
    python 地名地址解析(省、市、区县)
    将jupyter notebook嵌入博客园的博客
    Adaboost、GBDT、xgboost的原理基础
    数据预处理:分类变量实体嵌入做特征提取
    类不平衡问题的处理办法
    word2vec原理
  • 原文地址:https://www.cnblogs.com/DMoon/p/5329845.html
Copyright © 2011-2022 走看看