[loj2245]魔法森林

枚举携带的"A型守护精灵"数$A_{0}$,那么即只能经过$A_{i}\le A_{0}$的边,并最小化1到$n$路径上最大的$B_{i}$

将所有边按照$A_{i}$从小到大排序,那么前者即不断加入边,后者通过LCT维护$B_{i}$的最小生成树即可

具体的,将每一条边拆成一个点,向对应的两端点连边,加入一条边时查询对应环(若不产生环则直接加入)上$B_{i}$最大的边并替换即可

时间复杂度为$o(m\log m)$,可以通过

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 150005
  4 struct Data{
  5     int x,y,a,b;
  6     bool operator < (const Data &k)const{
  7         return a<k.a;
  8     }
  9 }e[N];
 10 multiset<int>S;
 11 int n,m,ans,st[N],fa[N],sz[N],rev[N],val[N],mx[N],ch[N][2];
 12 int which(int k){
 13     return ch[fa[k]][1]==k;
 14 }
 15 int check(int k){
 16     return ch[fa[k]][which(k)]==k;
 17 }
 18 int get_max(int x,int y){
 19     if (e[x].b>e[y].b)return x;
 20     return y;
 21 }
 22 void upd(int k){
 23     rev[k]^=1;
 24     swap(ch[k][0],ch[k][1]);
 25 }
 26 void up(int k){
 27     sz[k]=sz[ch[k][0]]+sz[ch[k][1]]+1;
 28     mx[k]=get_max(get_max(mx[ch[k][0]],mx[ch[k][1]]),val[k]);
 29 }
 30 void down(int k){
 31     if (rev[k]){
 32         if (ch[k][0])upd(ch[k][0]);
 33         if (ch[k][1])upd(ch[k][1]);
 34         rev[k]=0;
 35     }
 36 }
 37 void rotate(int k){
 38     int f=fa[k],g=fa[f],p=which(k);
 39     fa[k]=g;
 40     if (check(f))ch[g][which(f)]=k;
 41     fa[ch[k][p^1]]=f,ch[f][p]=ch[k][p^1];
 42     fa[f]=k,ch[k][p^1]=f;
 43     up(f),up(k);
 44 }
 45 void splay(int k){
 46     for(int i=k;;i=fa[i]){
 47         st[++st[0]]=i;
 48         if (!check(i))break;
 49     }
 50     while (st[0])down(st[st[0]--]);
 51     for(int i=fa[k];check(k);i=fa[k]){
 52         if (check(i)){
 53             if (which(i)==which(k))rotate(i);
 54             else rotate(k);
 55         }
 56         rotate(k);
 57     }
 58 }
 59 void access(int k){
 60     int lst=0;
 61     while (k){
 62         splay(k);
 63         ch[k][1]=lst,up(k);
 64         lst=k,k=fa[k];
 65     }
 66 }
 67 void make_root(int k){
 68     access(k);
 69     splay(k);
 70     upd(k);
 71 }
 72 int find_root(int k){
 73     access(k);
 74     splay(k);
 75     while (ch[k][0]){
 76         down(k);
 77         k=ch[k][0];
 78     }
 79     splay(k);
 80     return k;
 81 }
 82 void add(int x,int y){
 83     make_root(x);
 84     make_root(y);
 85     fa[y]=x;
 86 }
 87 void del(int x,int y){
 88     make_root(x);
 89     access(y);
 90     splay(x);
 91     fa[y]=ch[x][1]=0;
 92     up(x);
 93 }
 94 int query(int x,int y){
 95     make_root(x);
 96     if (find_root(y)!=x)return -1;
 97     return mx[x];
 98 }
 99 int main(){
100     scanf("%d%d",&n,&m);
101     for(int i=1;i<=m;i++)scanf("%d%d%d%d",&e[i].x,&e[i].y,&e[i].a,&e[i].b);
102     sort(e+1,e+m+1);
103     for(int i=1;i<=m;i++)val[i+n]=mx[i+n]=i;
104     for(int i=1;i<=m;i++)add(e[i].x,i+n);
105     ans=1e9;
106     for(int i=1;i<=m;i++){
107         int s=query(e[i].y,i+n);
108         if (s!=i){
109             if (s>0)del(e[s].y,s+n);
110             add(e[i].y,i+n);
111         }
112         s=query(1,n);
113         if (s>0)ans=min(ans,e[i].a+e[s].b);
114     }
115     if (ans==1e9)ans=-1;
116     printf("%d\n",ans);
117     return 0;
118 } 
View Code

 

posted @ 2021-08-31 15:35  PYWBKTDA  阅读(33)  评论(0编辑  收藏  举报