zoukankan      html  css  js  c++  java
  • 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
    ", ans);
    161     return 0;
    162 }
    View Code
  • 相关阅读:
    c语言中统计字符串中数字出现的次数
    tyvj1294 小v的舞会
    tyvj1114 搭建双塔
    tyvj1193 括号序列
    tyvj1113 魔族密码
    tyvj1102 单词的划分
    tyvj1097 mm不哭
    tyvj1189 盖房子
    tyvj1098 任务安排
    tyvj1144 股票
  • 原文地址:https://www.cnblogs.com/MingSD/p/9492883.html
Copyright © 2011-2022 走看看