bzoj 3669 魔法森林

题解:先将所有的边按照 a 从小达到排序, 类似于最小生成树的方法, 用并查集维护2个点是否联通, 每次处理一条新的边的时候, 先判断这2个点是否联通, 如果不连通就把这2个点连边,如果这2个点已经联通了,那么如果新加上这条边之后就会和原来的链构成一个环, 我们再去掉这个环上b最大的那条边, 每次处理完一条边就判断一下 1 和 n 的连通性, 然后更新答案。

 注意的就是 lct 不好维护边权, 我们把边权转化成点权,每次处理一条边的时候都新开一个节点, 这个节点上有花费,如果要连, 就把这原来边的2个端点都连新的节点。

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
  4 #define LL long long
  5 #define ULL unsigned LL
  6 #define fi first
  7 #define se second
  8 #define pb push_back
  9 #define lson l,m,rt<<1
 10 #define rson m+1,r,rt<<1|1
 11 #define lch(x) tr[x].son[0]
 12 #define rch(x) tr[x].son[1]
 13 #define max3(a,b,c) max(a,max(b,c))
 14 #define min3(a,b,c) min(a,min(b,c))
 15 typedef pair<int,int> pll;
 16 const int inf = 0x3f3f3f3f;
 17 const LL INF = 0x3f3f3f3f3f3f3f3f;
 18 const LL mod =  (int)1e9+7;
 19 const int N = 5e5 + 100;
 20 struct Node{
 21     int rev, rt;
 22     int son[2], pre;
 23     int mx, val, id;
 24     void init(){
 25         rt = 1; rev = pre = son[0] = son[1] = 0;
 26         mx = val = id = 0;
 27     }
 28 }tr[N];
 29 void Push_Rev(int x){
 30     if(!x) return ;
 31     swap(lch(x), rch(x));
 32     tr[x].rev ^= 1;
 33 }
 34 void Push_Up(int x){
 35     if(!x) return ;
 36     tr[x].mx = tr[x].val, tr[x].id = x;
 37     if(tr[x].mx < tr[lch(x)].mx) tr[x].mx = tr[lch(x)].mx, tr[x].id = tr[lch(x)].id;
 38     if(tr[x].mx < tr[rch(x)].mx) tr[x].mx = tr[rch(x)].mx, tr[x].id = tr[rch(x)].id;
 39 }
 40 void Push_Down(int x){
 41    if(tr[x].rev){
 42         tr[x].rev = 0;
 43         Push_Rev(lch(x));
 44         Push_Rev(rch(x));
 45     }
 46 }
 47 void Rev(int x){
 48     if(!tr[x].rt) Rev(tr[x].pre);
 49     Push_Down(x);
 50 }
 51 
 52 void rotate(int x){
 53     if(tr[x].rt) return;
 54     int y = tr[x].pre, z = tr[y].pre;
 55     int k = (rch(y) == x);
 56     tr[y].son[k] = tr[x].son[k^1];
 57     tr[tr[y].son[k]].pre = y;
 58     tr[x].son[k^1] = y;
 59     tr[y].pre = x;
 60     tr[x].pre = z;
 61     if(tr[y].rt) tr[y].rt = 0, tr[x].rt = 1;
 62     else tr[z].son[rch(z) == y] = x;
 63     Push_Up(y);
 64 }
 65 void Splay(int x){
 66      Rev(x);
 67      while(!tr[x].rt){
 68         int y = tr[x].pre, z = tr[y].pre;
 69         if(!tr[y].rt){
 70             if(( x == rch(y) ) != (y == rch(z))) rotate(y);
 71             else rotate(x);
 72         }
 73         rotate(x);
 74     }
 75     Push_Up(x);
 76 }
 77 void Access(int x){
 78     int y = 0;
 79     do{
 80         Splay(x);
 81         tr[rch(x)].rt = 1;
 82         rch(x) = y;
 83         tr[y].rt = 0;
 84         Push_Up(x);
 85         y = x;
 86         x = tr[x].pre;
 87     }while(x);
 88 }
 89 void Make_rt(int x){
 90     Access(x);
 91     Splay(x);
 92     Push_Rev(x);
 93 }
 94 void link(int u, int v){
 95     Make_rt(u);
 96     tr[u].pre = v;
 97 }
 98 void cut(int u, int v){
 99     Make_rt(u);
100     Access(v);
101     Splay(v);
102     tr[lch(v)].pre = 0;
103     tr[lch(v)].rt = 1;
104     tr[v].pre = 0;
105     lch(v) = 0;
106 }
107 bool judge(int u, int v){
108     while(tr[u].pre) u = tr[u].pre;
109     while(tr[v].pre) v = tr[v].pre;
110     return u == v;
111 }
112 int n, m, u, v;
113 int pre[N];
114 struct Edge{
115     int u, v, a, b;
116     bool operator < (const Edge & x) const {
117         if(a == x.a) return b < x.b;
118         return a < x.a;
119     }
120 }e[N];
121 int Find(int x){
122     if(x == pre[x]) return x;
123     return pre[x] = Find(pre[x]);
124 }
125 int main(){
126     scanf("%d%d", &n, &m);
127     for(int i = 1; i <= n+m; i++)
128         tr[i].init(), pre[i] = i;
129     for(int i = 1; i <= m; i++)
130         scanf("%d%d%d%d", &e[i].u, &e[i].v, &e[i].a, &e[i].b);
131     sort(e+1, e+1+m);
132     int ans = inf;
133     for(int i = 1; i <= m; i++){
134         tr[i+n].val = tr[i+n].mx = e[i].b;
135         int u = e[i].u, v = e[i].v;
136         if(Find(u) != Find(v)){
137             link(u, i+n);
138             link(v, i+n);
139             pre[Find(u)] = pre[Find(v)] = i+n;
140         }
141         else {
142             Make_rt(u);
143             Access(v);
144             Splay(v);
145             int k = tr[v].id;
146             if(tr[v].mx > e[i].b){
147                 cut(u, k); cut(v, k);
148                 link(u, i+n);
149                 link(v, i+n);
150             }
151         }
152         if(Find(1) == Find(n)){
153             Make_rt(1);
154             Access(n);
155             Splay(n);
156             ans = min(ans, e[i].a + tr[n].mx);
157         }
158     }
159     if(ans == inf) ans = -1;
160     printf("%d\n", ans);
161     return 0;
162 }
View Code

猜你喜欢

转载自www.cnblogs.com/MingSD/p/9492883.html