BZOJ3669 [NOI2014]魔法森林

Posted goldgenius

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3669 [NOI2014]魔法森林相关的知识,希望对你有一定的参考价值。

【问题描述】

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

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

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

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

【输入格式】

第1行包含两个整数N,M,表示无向图共有N个节点,M条边。 接下来M行,第行包含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

【输入样例2】

3 1
1 2 1 

 
【输出样例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。
 
【数据范围】

2<=n<=50,000

0<=m<=100,000

1<=ai ,bi<=50,000
 

正解:LCT

解题报告:读入的边按a排序,动态加边,维护一颗生成树,如果1到n联通的话用路径上的最大b和当前加的边的a的和更新答案。

 

  1 #include <iostream>
  2 #include <iomanip>
  3 #include <cstdlib>
  4 #include <cstdio>
  5 #include <cmath>
  6 #include <cstring>
  7 #include <algorithm>
  8 #include <string>
  9 #define RG register
 10 #define inl inline
 11 const int N = 200050;
 12 const int M = 50050;
 13 const int inf = 2147483641;
 14 
 15 using namespace std;
 16 
 17 inl int gi(){
 18     char ch=getchar();RG int x=0;
 19     while(ch<0 || ch>9) ch=getchar();
 20     while(ch>=0 && ch<=9) x=x*10+ch-0,ch=getchar();
 21     return x;
 22 }
 23 
 24 int c[N][2],fa[N],mx[N],rev[N],st[N],w[N],ans,f[N];
 25 
 26 struct date{
 27     int l,r,a,b;
 28 }rd[N];
 29 
 30 int find(int a){
 31     return a==f[a]?a:f[a]=find(f[a]);
 32 }
 33 
 34 void pushdown(int x){
 35     if (rev[x]==0) return;
 36     RG int l=c[x][0],r=c[x][1];
 37     rev[x]^=1,rev[l]^=1,rev[r]^=1;
 38     swap(c[x][0],c[x][1]);
 39     return;
 40 }
 41 
 42 int isroot(int x){
 43     return c[fa[x]][0]!=x && c[fa[x]][1]!=x;
 44 }
 45 
 46 void update(int x){
 47     mx[x]=x;
 48     RG int l=c[x][0],r=c[x][1];
 49     if (w[mx[l]]>w[mx[x]]) mx[x]=mx[l];
 50     if (w[mx[r]]>w[mx[x]]) mx[x]=mx[r];
 51     return;
 52 }
 53 
 54 void rotate(int x){
 55     RG int l,r,y=fa[x],z=fa[y];
 56     if (c[y][0]==x) l=0;
 57     else l=1;r=l^1;
 58     if (!isroot(y))
 59         if (c[z][0]==y) c[z][0]=x;
 60         else c[z][1]=x;
 61     fa[x]=z,fa[y]=x,fa[c[x][r]]=y;
 62     c[y][l]=c[x][r],c[x][r]=y;
 63     update(y),update(x);
 64     return;
 65 }
 66 
 67 void splay(int x){
 68     RG int tot=0;st[++tot]=x;
 69     for (RG int i=x; !isroot(i); i=fa[i]) st[++tot]=fa[i];
 70     for (RG int i=tot; i; --i) pushdown(st[i]);
 71     while(!isroot(x)){
 72         RG int y=fa[x],z=fa[y];
 73         if (!isroot(y))
 74             if (c[y][0]==x ^ c[z][0]==y) rotate(x);
 75             else rotate(y);
 76         rotate(x);
 77     }
 78     return;
 79 }
 80 
 81 void access(int x){
 82     RG int t=0;
 83     while(x){
 84         splay(x);
 85         c[x][1]=t;
 86         t=x,x=fa[x],update(x);
 87     }
 88     return;
 89 }
 90 
 91 void rever(int x){
 92     access(x);
 93     splay(x),rev[x]^=1;
 94     return;
 95 }
 96 
 97 void cut(int x,int y){
 98     rever(x);
 99     access(y);
100     splay(y);
101     fa[x]=c[y][0]=0,update(y);
102     return;
103 }
104 
105 void link(int x,int y){
106     rever(x),fa[x]=y;
107     return;
108 }
109 
110 int cmp(date a,date b){
111     return a.a<b.a;
112 }
113 
114 int query(int x,int y){
115     rever(x);
116     access(y);
117     splay(y);
118     return mx[c[y][0]];
119 }
120 
121 int MIN(int a,int b){
122     return a<b?a:b;
123 }
124 
125 int main(){
126     RG int n=gi(),m=gi(),s=n+m;
127     for (RG int i=1; i<=s; ++i) f[i]=i;
128     for (RG int i=1; i<=m; ++i)
129         rd[i]=(date){gi(),gi(),gi(),gi()};
130     sort(rd+1,rd+m+1,cmp);ans=inf;
131     for (RG int i=1; i<=m; ++i){
132         RG int l=rd[i].l,r=rd[i].r,d,g;
133         w[n+i]=rd[i].b,f[n+i]=n+i;
134         if (find(l)==find(r)){
135             RG int s=query(l,r);
136             if (w[s]>rd[i].b){
137                 cut(rd[s-n].l,s);
138                 cut(rd[s-n].r,s);
139                 link(rd[i].l,i+n);
140                 link(rd[i].r,i+n);
141             }
142             else continue;
143         }
144         else{
145             f[find(l)]=find(r);
146             link(rd[i].l,i+n);
147             link(rd[i].r,i+n);
148         }
149         if (find(1)==find(n))
150             ans=MIN(ans,rd[i].a+w[query(1,n)]);
151     }
152     if (ans==inf) printf("-1");
153     else printf("%d",ans);
154     return 0;
155 }

 

以上是关于BZOJ3669 [NOI2014]魔法森林的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ3669][Noi2014]魔法森林

BZOJ3669[Noi2014]魔法森林 LCT

BZOJ 3669 Noi2014 魔法森林

BZOJ3669 [NOI2014]魔法森林

BZOJ3669Noi2014魔法森林(Link-Cut Tree)

NOI2014BZOJ3669UOJ#3魔法森林