洛谷P2387 [NOI2014]魔法森林
阿新 • • 發佈:2019-02-02
無法 date stream 找到 輸入輸出格式 我們 如何 文件的 adc 包含兩個權值 \(a_i\) 與 \(b_i\) 。若身上攜帶的 A 型守護精靈個數不少於 \(a_i\) ,且 B 型守護精靈個數不少於 \(b_i\) ,這條邊上的妖怪就不會對通過這條邊 的人發起攻擊。當且僅當通過這片魔法森林的過程中沒有任意一條邊的妖怪向 小 E 發起攻擊,他才能成功找到隱士。
由於攜帶守護精靈是一件非常麻煩的事,小 E 想要知道,要能夠成功拜訪到隱士,最少需要攜帶守護精靈的總個數。守護精靈的總個數為 A 型守護精靈的個數與 B 型守護精靈的個數之和。 條邊。 接下來 \(m\) 行,第\(i+ 1\) 行包含 \(4\) 個正整數 \(X_i,Y_i,a_i,b_i\),描述第 \(i\) 條無向邊。 其中 \(X_i\)與 \(Y_i\)為該邊兩個端點的標號,\(a_i\) 與 \(b_i\) 的含義如題所述。 註意數據中可能包含重邊與自環。
大於A的值的邊都會被刪去,隨著A的值的不斷增大,會不斷有邊加入。
使用動態樹維護生成樹兩個節點之間\(b_i\)的最大值,那麽每當一條新的邊加入生成樹時,我們可以求出這條新邊兩個端點之前原來的\(b_i\)的最大值,如果這個最大值比\(b_i\)大,那麽找到這條\(b_i\)最大的邊並把它從生成樹中刪除,動態樹中斷開,並把新邊加入,操作時算一下最小值最後輸出就行了。
洛谷P2387 [NOI2014]魔法森林
題目描述
為了得到書法大家的真傳,小 E 同學下定決心去拜訪住在魔法森林中的隱 士。魔法森林可以被看成一個包含 \(n\) 個節點 \(m\) 條邊的無向圖,節點標號為 \(1,2,3,…,n\),邊標號為 \(1,2,3,…,m\)。初始時小 E 同學在 \(1\) 號節點,隱士則住在 \(n\) 號節點。小 E 需要通過這一片魔法森林,才能夠拜訪到隱士。
魔法森林中居住了一些妖怪。每當有人經過一條邊的時候,這條邊上的妖怪 就會對其發起攻擊。幸運的是,在 \(1\) 號節點住著兩種守護精靈:A 型守護精靈與 B 型守護精靈。小 E 可以借助它們的力量,達到自己的目的。
只要小 E 帶上足夠多的守護精靈,妖怪們就不會發起攻擊了。具體來說,無 向圖中的每一條邊 \(e_i\)
由於攜帶守護精靈是一件非常麻煩的事,小 E 想要知道,要能夠成功拜訪到隱士,最少需要攜帶守護精靈的總個數。守護精靈的總個數為 A 型守護精靈的個數與 B 型守護精靈的個數之和。
輸入輸出格式
輸入格式:
輸入文件的第 \(1\) 行包含兩個整數 \(n,m\),表示無向圖共有 \(n\) 個節點,\(m\)
輸出格式:
輸出一行一個整數:如果小 E 可以成功拜訪到隱士,輸出小 E 最少需要攜 帶的守護精靈的總個數;如果無論如何小 E 都無法拜訪到隱士,輸出 -1
。
思路
動態樹求解動態最小生成樹
從小到大枚舉A型守護精靈的個數,很顯然A的值只會等於\(a_i\)中的一個。
當A的值確定之後,原圖中的\(a_i\)
使用動態樹維護生成樹兩個節點之間\(b_i\)的最大值,那麽每當一條新的邊加入生成樹時,我們可以求出這條新邊兩個端點之前原來的\(b_i\)的最大值,如果這個最大值比\(b_i\)大,那麽找到這條\(b_i\)最大的邊並把它從生成樹中刪除,動態樹中斷開,並把新邊加入,操作時算一下最小值最後輸出就行了。
CODE
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 200010
struct Node{
int u,v,a,b;
Node(){}
Node(int u,int v,int a,int b):u(u),v(v),a(a),b(b){}
bool operator < (const Node &aa) const{
return a<aa.a;
}
}p[MAXN];
int ch[MAXN][2],fa[MAXN],maxid[MAXN],q[MAXN],linkline[MAXN][2],val[MAXN];
bool rev[MAXN];
int i,j,k,m,n,x,y,u,v,a,b,qtop,ans,ncnt;
char readc;
void read(int &n){
while((readc=getchar())<48||readc>57);
n=readc-48;
while((readc=getchar())>=48&&readc<=57) n=n*10+readc-48;
}
int get(int x){
return ch[fa[x]][1]==x;
}
bool isroot(int x){
return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
}
void pushup(int x){
int tmp=x;
if(val[tmp]<val[maxid[ch[x][0]]]) tmp=maxid[ch[x][0]];
if(val[tmp]<val[maxid[ch[x][1]]]) tmp=maxid[ch[x][1]];
maxid[x]=tmp;
}
void pushdown(int x){
if(rev[x]){
swap(ch[x][0],ch[x][1]);
rev[ch[x][0]]^=1,rev[ch[x][1]]^=1;
rev[x]=false;
}
}
void rotate(int x){
int y=fa[x],z=fa[y],k=get(x),w=ch[x][k^1];
ch[y][k]=w,fa[w]=y;
if(!isroot(y)) ch[z][get(y)]=x;
fa[x]=z;
ch[x][k^1]=y,fa[y]=x;
pushup(y),pushup(x);
}
void splay(int x){
q[qtop=1]=x;
for(int i=x;!isroot(i);i=fa[i]) q[++qtop]=fa[i];
for(int i=qtop;i>=1;i--) pushdown(q[i]);
while(!isroot(x)){
int y=fa[x];
if(!isroot(y)){
if(get(x)==get(y)) rotate(y); else rotate(x);
}
rotate(x);
}
pushup(x);
}
void access(int x){
for(int y=0;x;y=x,x=fa[x]){
splay(x),ch[x][1]=y;
pushup(x);
}
}
void makeroot(int x){
access(x);
splay(x);
rev[x]^=1;
}
void split(int x,int y){
makeroot(x);
access(y);
splay(y);
}
int findroot(int x){
access(x);
splay(x);
while(ch[x][0]) pushdown(x),x=ch[x][0];
return x;
}
void link(int x,int y){
makeroot(x);
if(findroot(y)!=x) fa[x]=y;
}
void cut(int x,int y){
split(x,y);
if(findroot(y)==x&&fa[x]==y&&ch[x][1]==0){
fa[x]=0;
ch[y][0]=0;
pushup(y);
}
}
void update(int id){
int x=p[id].u,y=p[id].v;
if(x==y) return;
makeroot(x);
if(findroot(y)!=x){
val[++ncnt]=p[id].b;
link(x,ncnt);
linkline[ncnt][0]=x;
link(y,ncnt);
linkline[ncnt][1]=y;
}else{
split(x,y);
int tmp=maxid[y];
if(p[id].b<val[tmp]){
cut(linkline[tmp][0],tmp);
cut(linkline[tmp][1],tmp);
val[tmp]=p[id].b;
link(x,tmp);
link(y,tmp);
linkline[tmp][0]=x,linkline[tmp][1]=y;
}
}
}
int query(){
if(findroot(1)!=findroot(n)) return 1000000000;
split(1,n);
return val[maxid[n]];
}
int main(){
ans=1000000000;
read(n),read(m);
for(i=1;i<=m;i++){
read(x),read(y),read(a),read(b);
if(x>y) swap(x,y);
p[i]=Node(x,y,a,b);
}
ncnt=n;
sort(p+1,p+m+1);
for(i=1;i<=m;i++){
update(i);
ans=min(ans,query()+p[i].a);
}
if(ans==1000000000){
printf("-1\n");
}else{
printf("%d\n",ans);
}
return 0;
}
洛谷P2387 [NOI2014]魔法森林