zoukankan      html  css  js  c++  java
  • bzoj 3669: [Noi2014] 魔法森林 LCT版

    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

    题目即要求使1和n连通的使a的最大值+b的最大值最小。。。

    对于这种一条边有两种权限制的题目,一般都是限制住一种边的条件再对另一条边进行处理。。。

    这题的暴力做法还是可以YY的。。。

    首先最大边最小是显然满足最小生成树的性质的。。。

    所以按a的大小加入满足a的边,再以这些边跑按照b跑Kruskal。。。竟然有70分。。。

    然后我傻逼的YY了一个二分a的高骗,竟然骗了80分(这个答案显然是没有单调性的,应该会WA飞,然而有80分,时间贼快)

    正解可以用SPFA动态加边也可以用LCT。。。。。

    如果要用LCT的话就要知道一个叫做另类MST的鬼东西。。。网管的水管局长PPT上有。。。

    大致做法就是先随意构一棵生成树,不断加边,如果形成了环,就把环上边权最大的删掉。。。

    这样的话我们就可以按a的大小加入满足a的边然后动态维护加了边之后的b的最小生成树。。。这样的好处就是每次无需重新构MST。。。

    那么对于这个操作LCT显然是可以胜任的。。。

    这题还要用到一个很巧妙的东西,就是把边作为一个点加进去。。因为LCT并不能维护边权。。。

    对与边i就是类似这样:lnk(i+n,e[i].x),lnk(i+n,e[i].y);

    下面附上代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cstring>
      5 using namespace std;
      6 const int N=1000500;
      7 int gi()
      8 {
      9     int x=0;
     10     char ch=getchar();
     11     while(ch<'0'||ch>'9') ch=getchar();
     12     while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
     13     return x;
     14 }
     15 int fa[N],c[N][2],st[N],v[N],maxn[N],n,m,ans=1000000007;
     16 bool rev[N];
     17 struct data
     18 {
     19     int u,v,a,b;
     20 } edge[N];
     21 bool isroot(int x)
     22 {
     23      return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
     24 }
     25 void modify(int x)
     26 {
     27     int l=c[x][0],r=c[x][1];
     28     maxn[x]=x;
     29     if(v[maxn[x]]<v[maxn[l]]) maxn[x]=maxn[l];
     30     if(v[maxn[x]]<v[maxn[r]]) maxn[x]=maxn[r];
     31 }
     32 void pushdown(int x)
     33 {
     34   int l=c[x][0],r=c[x][1];
     35   if(rev[x])
     36     {
     37       rev[x]^=1;rev[l]^=1;rev[r]^=1;
     38       swap(c[x][0],c[x][1]);
     39     }
     40 }
     41 void rotate(int x)
     42 {
     43     int y=fa[x],z=fa[y],l,r;
     44     if(c[y][0]==x)l=0;else l=1;r=l^1;
     45     if(!isroot(y))
     46     {
     47         if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;
     48     }
     49     fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
     50     c[y][l]=c[x][r];c[x][r]=y;
     51     modify(y);modify(x);
     52 }
     53 void splay(int x)
     54 {
     55   int top=0;st[++top]=x;
     56   for(int i=x;!isroot(i);i=fa[i])
     57     {
     58       st[++top]=fa[i];
     59     }
     60   for(int i=top;i;i--) pushdown(st[i]);
     61   while(!isroot(x))
     62     {
     63       int y=fa[x],z=fa[y];
     64       if(!isroot(y))
     65     {
     66       if((c[y][0]==x)^(c[z][0]==y)) rotate(x);
     67       else rotate(y);
     68     }
     69       rotate(x);
     70     }
     71 }
     72 void access(int x)
     73 {
     74     int t=0;
     75     while(x)
     76     {
     77         splay(x);
     78         c[x][1]=t;
     79         t=x;x=fa[x];
     80     }
     81 }
     82 void rever(int x)
     83 {
     84     access(x);splay(x);rev[x]^=1;
     85 }
     86 void lnk(int x,int y)
     87 {
     88   rever(x);fa[x]=y;splay(x);
     89 }
     90 void cut(int x,int y)
     91 {
     92   rever(x);access(y);splay(y);c[y][0]=fa[x]=0;
     93 }
     94 int query(int x,int y)
     95 {
     96     rever(x);access(y);splay(y);
     97     return maxn[c[y][0]];
     98 }
     99 int find(int x)
    100 {
    101     access(x);splay(x);
    102     int y=x;
    103     while(c[y][0]) y=c[y][0];
    104     return y;
    105 }
    106 bool cmp(data a,data b)
    107 {
    108     return a.a<b.a;
    109 }
    110 int main()
    111 {
    112     n=gi();m=gi();
    113     for(int i=1; i<=m; i++)
    114     {
    115         edge[i].u=gi();edge[i].v=gi();edge[i].a=gi();edge[i].b=gi();
    116     }
    117     for(int i=1;i<=m+n;i++) maxn[i]=i;
    118     sort(edge+1,edge+1+m,cmp);
    119     for(int i=1; i<=m; i++)
    120     {
    121         int x=edge[i].u,y=edge[i].v;
    122         if(find(x)!=find(y))
    123         {
    124             v[n+i]=edge[i].b;
    125             lnk(x,n+i);lnk(y,n+i);
    126         }
    127         else
    128         {
    129             int maxm=query(x,y);
    130             if(edge[i].b<v[maxm])
    131             {
    132                 cut(maxm,edge[maxm-n].u);
    133                 cut(maxm,edge[maxm-n].v);
    134                 v[n+i]=edge[i].b;
    135                 lnk(x,n+i);lnk(y,n+i);
    136             }
    137         }
    138         if(find(1)==find(n)) ans=min(ans,edge[i].a+v[query(1,n)]);
    139     }
    140     if(ans==1000000007) cout<<-1<<endl;
    141     else cout<<ans;
    142 }
  • 相关阅读:
    VIVADO固化
    Keil MDK 编译器 AC5 和 AC6 优化选项重要内容和区别
    STM32时钟
    STlink/v2中SWD模式连线方式
    搭载M33内核,支持最新蓝牙5.1,晚到的DA1469x生正逢时
    超全国内外蓝牙芯片原厂总结(含芯片型号)
    芯片封装类型大全
    国务院办公厅关于2012年部分节假日安排的通知
    美国摇滚乐队Metro致敬黄家驹,全粤语翻唱Beyond经典《海阔天空》
    国务院办公厅发布2010年部分节假日安排通知
  • 原文地址:https://www.cnblogs.com/qt666/p/6490941.html
Copyright © 2011-2022 走看看