差不多理解板子之后,写了一些奇怪的题。

但是还是那个问题:树剖真好使

 

魔法森林mikufun说这个是傻逼题。

为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐士。

魔法森林可以被看成一个包含n个节点m条边的无向图,节点标号为1~n,边标号为1~m

初始时小 E 同学在号节点 ,隐士则住在n号节点。小 E 需要通过这一片魔法森林,才能够拜访到隐士。

魔法森林中居住了一些妖怪。每当有人经过一条边的时候,这条边上的妖怪就会对其发起攻击。

幸运的是,在1号节点住着两种守护精灵:A型守护精灵与B型守护精灵。小 E 可以借助它们的力量,达到自己的目的。

只要小 E 带上足够多的守护精灵,妖怪们就不会发起攻击了。具体来说,无向图中的每一条边包含两个权值$A_i$与$B_i$

若身上携带的 A 型守护精灵个数不少于$A_i$,且B型守护精灵个数不少$B_i$,这条边上的妖怪就不会对通过这条边的人发起攻击。

当且仅当通过这片魔法森林的过程中没有任意一条边的妖怪向小 E 发起攻击,他才能成功找到隐士。

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

守护精灵的总个数为A型守护精灵的个数与B型守护精灵的个数之和。$n \le 50000,m \le 100000$

只有两个参数,肯定有点好YY的吧。

挺套路的,一维排序,然后就会好做的多吧。

所以边按照A排序,维护最小生成树,然后不断加入B小A大的边更新答案。

类似于水管局长。也是那种「替代生成树上最大边」的思路。不过是最值。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define S 150005
 4 #define lc c[p][0]
 5 #define rc c[p][1]
 6 struct edge{
 7     int a,b,x,y;
 8     friend bool operator<(edge p,edge q){return p.a<q.a;}
 9 }E[S];
10 int f[S],n,m,c[S][2],w[S],P[S],lz[S],s[S],ans=998244353,k[S];
11 int get(int p){return p>n?E[p-n].b:-998244353;}
12 void up(int p){
13     if(w[lc]>w[rc])w[p]=w[lc],P[p]=P[lc];else w[p]=w[rc],P[p]=P[rc];
14     if(get(p)>w[p])w[p]=get(p),P[p]=p;//printf("%d %d %d %d %d\n",p,w[p],lc,rc,get(p));
15 }
16 void rev(int p){lc^=rc^=lc^=rc;lz[p]^=1;}
17 void down(int p){if(lz[p])rev(lc),rev(rc),lz[p]=0;}
18 bool nr(int p){return c[f[p]][0]==p||c[f[p]][1]==p;}
19 void rotate(int p){
20     int fa=f[p],gr=f[fa],dir=c[fa][1]==p,br=c[p][!dir];
21     c[fa][dir]=br;c[p][!dir]=fa;if(nr(fa))c[gr][c[gr][1]==fa]=p;
22     f[p]=gr;f[fa]=p;f[br]=fa;up(fa);
23 }
24 void splay(int p){int tp=0,fa,gr;s[++tp]=p;
25     for(int r=p;nr(r);s[++tp]=r=f[r]);for(;tp;down(s[tp--]));
26     while(nr(p)){fa=f[p],gr=f[fa];
27         if(nr(fa))rotate(c[gr][1]==fa^c[fa][1]==p?fa:p);rotate(p);    
28     }up(p);
29 }
30 void access(int p){for(int r=0;p;p=f[r=p])splay(p),rc=r,up(p);}
31 void make(int p){access(p);splay(p);rev(p);}
32 void split(int x,int y){make(x);access(y);splay(y);}
33 void link(int x,int y){make(x);f[x]=y;}
34 void cut(int x,int y){split(x,y);c[y][0]=f[x]=0;up(y);}
35 int F(int p){return p==k[p]?p:k[p]=F(k[p]);}
36 int main(){
37     scanf("%d%d",&n,&m);w[0]=-998244353;
38     for(int i=1;i<=n;++i)k[i]=i;
39     for(int i=1;i<=m;++i)scanf("%d%d%d%d",&E[i].x,&E[i].y,&E[i].a,&E[i].b);
40     sort(E+1,E+1+m);for(int i=1;i<=n+m;++i)up(i);int i=1,x,y;
41     for(int i=1,p;i<=m;++i){x=E[i].x,y=E[i].y;
42         if(F(x)!=F(y)){k[F(x)]=F(y);link(x,i+n);link(y,i+n);goto cal;}
43         split(x,y);if(w[y]<E[i].b)continue;p=P[y]-n;
44         cut(p+n,E[p].x);cut(p+n,E[p].y);link(i+n,E[i].x);link(i+n,E[i].y);
45 cal:    if(F(1)==F(n))split(n,1),ans=min(ans,E[i].a+w[1]);
46     }printf("%d\n",ans==998244353?-1:ans);
47 }
View Code

相关文章: