差不多理解板子之后,写了一些奇怪的题。
但是还是那个问题:树剖真好使。
魔法森林: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 }