BZOJ3669 [NOI2014]魔法森林
【问题描述】
为了得到书法大家的真传,小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型守护精灵的个数之和。
【输入格式】
第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
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 }