zoukankan      html  css  js  c++  java
  • [NOI2014]魔法森林

    题目描述

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

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

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

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

    输入输出格式

    输入格式:

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

    输出格式:

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

    输入输出样例

    输入样例#1: 复制
    4 5 
    1 2 19 1 
    2 3 8 12 
    2 4 12 15 
    1 3 17 8 
    3 4 1 17 
    输出样例#1: 复制
    32
    
    输入样例#2: 复制
    3 1 
    1 2 1 1 
    输出样例#2: 复制
    -1

    说明

    • 解释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

    小 E 无法从 1 号节点到达 3 号节点,故输出-1。

    LCT做fa♂:

    按a排序,动态加边,当不形成环时直接加入

    否则找到u~v路径上b最大的边替换

    查询1~n中b的最大与当前加入的最大的a相加

    但是LCT按边维护会很麻烦

    解决方法是化边权为点权,即在(u->v)之间加一个点pos,点权为边权

    似乎还有动态SPFA做fa♂

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<cmath>
      6 using namespace std;
      7 struct ZYYS
      8 {
      9   int u,v,a,b;
     10 }e[400001];
     11 int w[400005],ch[400005][2],rev[400005],pre[400005],isrt[400005],n,m,k[400005];
     12 int Maxi[400005],inf=2e9,pos,A[400005],B[400005],ans;
     13 bool cmp(ZYYS x,ZYYS y)
     14 {
     15   return x.a<y.a;
     16 }
     17 void pushup(int o)
     18 {
     19   if (!o) return;
     20   Maxi[o]=o;
     21   if (w[Maxi[ch[o][0]]]>w[Maxi[o]])
     22     {
     23       Maxi[o]=Maxi[ch[o][0]];
     24     }
     25   if (w[Maxi[ch[o][1]]]>w[Maxi[o]])
     26     {
     27       Maxi[o]=Maxi[ch[o][1]];
     28     }
     29 }
     30 void pushdown(int o)
     31 {
     32   if (!o) return;
     33   if (rev[o])
     34     {
     35       int ls=ch[o][0],rs=ch[o][1];
     36       rev[ls]^=1;
     37       swap(ch[ls][0],ch[ls][1]);
     38       rev[rs]^=1;
     39       swap(ch[rs][0],ch[rs][1]);
     40       rev[o]=0;
     41     }
     42 }
     43 void push(int o)
     44 {
     45   if (isrt[o]==0) push(pre[o]);
     46   pushdown(o);
     47 }
     48 void rotate(int o,bool kind)
     49 {
     50   int p=pre[o];
     51   ch[p][!kind]=ch[o][kind];pre[ch[o][kind]]=p;
     52   if (isrt[p]) isrt[p]=0,isrt[o]=1;
     53   else ch[pre[p]][ch[pre[p]][1]==p]=o;
     54   pre[o]=pre[p];
     55   ch[o][kind]=p;pre[p]=o;
     56   pushup(p);pushup(o);
     57 }
     58 void splay(int o)
     59 {
     60   push(o);
     61   while (isrt[o]==0)
     62     {
     63       if (isrt[pre[o]])
     64     rotate(o,ch[pre[o]][0]==o);
     65       else
     66     {
     67       int p=pre[o],kind=ch[pre[p]][0]==p;
     68       if (ch[p][kind]==o)
     69         rotate(o,!kind),rotate(o,kind);
     70       else rotate(p,kind),rotate(o,kind);
     71     }
     72     }
     73 }
     74 void access(int o)
     75 {
     76   int y=0;
     77   while (o)
     78     {
     79       splay(o);
     80       isrt[ch[o][1]]=1;
     81       isrt[ch[o][1]=y]=0;
     82       pushup(o);
     83       y=o;o=pre[o];
     84     }
     85 }
     86 void makeroot(int o)
     87 {
     88   access(o);
     89   splay(o);
     90   rev[o]^=1;
     91   swap(ch[o][0],ch[o][1]);
     92 }
     93 void link(int x,int y)
     94 {
     95   makeroot(x);
     96   pre[x]=y;
     97 }
     98 void cut(int x,int y)
     99 {
    100   makeroot(x);
    101   access(y);splay(y);
    102   ch[y][0]=0;pre[x]=0;
    103   isrt[x]=1;
    104   pushup(y);
    105 }
    106 int find(int o)
    107 {
    108   access(o);splay(o);
    109   while (ch[o][0]) o=ch[o][0];
    110   return o;
    111 }
    112 int query(int u,int v)
    113 {
    114   if (find(u)!=find(v)) return inf;
    115   makeroot(u);
    116   access(v);
    117   splay(v);
    118   return Maxi[v];
    119 }
    120 void update(int u,int v,int d)
    121 {
    122   int tmp=query(u,v);
    123   if (tmp==inf)
    124     {
    125       w[++pos]=d;
    126       A[pos]=u;B[pos]=v;
    127       link(u,pos);link(v,pos);
    128     }
    129   else
    130     {
    131       if (w[tmp]>d)
    132     {
    133       w[tmp]=d;
    134       cut(A[tmp],tmp);cut(B[tmp],tmp);
    135       A[tmp]=u;B[tmp]=v;
    136       link(u,tmp);link(v,tmp);
    137     }
    138     }
    139 }
    140 int main()
    141 {int i;
    142   cin>>n>>m;
    143   pos=n;
    144   for (i=1;i<=m;i++)
    145     {
    146       scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].a,&e[i].b);
    147     }
    148   for (i=1;i<=n+m;i++)
    149     isrt[i]=1;
    150   sort(e+1,e+m+1,cmp);
    151   ans=inf;
    152   for (i=1;i<=m;i++)
    153     {
    154       update(e[i].u,e[i].v,e[i].b);
    155       int tmp=query(1,n);
    156       if (tmp!=inf)
    157       ans=min(ans,w[tmp]+e[i].a);
    158     }
    159   if (ans==inf) ans=-1;
    160   printf("%d
    ",ans);
    161 }
  • 相关阅读:
    连通域搜索
    识别深色浅色
    新年,博客搬家了!!!
    C++11 —— 使用 thread 实现线程池
    自己实现的网络字节序转换函数
    GUI 编程 —— QT 的 QSlider 鼠标点击定位问题
    单生产者/单消费者 的 FIFO 无锁队列
    用模板类特化的方式实现工厂模式
    C++11 —— 简易的旋转锁类
    C++11 —— 获取 tuple 参数列表中指定数据类型的索引位置
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8298977.html
Copyright © 2011-2022 走看看