★★ 輸入文件:pwalk.in
輸出文件:pwalk.out
簡單對比
時間限制:1 s 內存限制:128 MBios
n個被天然地編號爲1..n奶牛(1<=n<=1000)正在一樣被方便的編號爲1..n的n個牧場中吃草。更加天然而方便的是,第i個奶牛就在第i個牧場中吃草。算法
其中的一些對牧場被總共的n-1條雙向通道的一條鏈接。奶牛能夠經過通道。第i條通道鏈接的兩個牧場是A_i和B_i(1<=A_i<=N;1<=B_i<=N)其長度是L_i(1<=L_i<=10000)。flask
通道只會鏈接兩個不一樣的牧場,因此這些通道使得整個牧場構成了一棵樹。數組
奶牛們是好交際的但願可以常常的訪問別的奶牛。急切地,它們但願你能經過告訴它們Q(1<=Q<=1000)對牧場的路徑來幫助他們安排旅行。(這裏將有Q個詢問,p1,p2(1<=p1<=n;1<=p1<=n))app
分數:200spa
問題名稱:pwalkpwa
輸入格式:調試
輸入樣例(file pwalk.in):code
4 2 2 1 2 4 3 2 1 4 3 1 2 3 2
輸出格式:blog
輸出樣例:
2 7
輸出說明:
詢問1:牧場1和牧場2的路徑長度爲2。 詢問2:3->4->1->2;總長爲7。
#include<iostream> using namespace std; #include<cstdio> #include<cstring> #define Er 20 #define N 1011 int deepp[N],head[N]; int father[N][Er]; struct Edge{ int v,last,w; }edge[N<<1]; int t=0,n,Q,ai,bi,li; int p1,p2; typedef long long ll; ll dis[N]={0}; void add_edge(int u,int v,int w) { ++t; edge[t].v=v; edge[t].w=w; edge[t].last=head[u]; head[u]=t; } void input() { scanf("%d%d",&n,&Q); for(int i=1;i<=n-1;++i) { scanf("%d%d%d",&ai,&bi,&li); add_edge(ai,bi,li); add_edge(bi,ai,li); } } void dfs(int k) { for(int l=head[k];l;l=edge[l].last) { if(!deepp[edge[l].v]) { deepp[edge[l].v]=deepp[k]+1; dis[edge[l].v]=dis[k]+edge[l].w; father[edge[l].v][0]=k; dfs(edge[l].v); } } } void pre_chuli() { for(int j=1;(1<<j)<=n;++j) for(int i=1;i<=n;++i) if(father[i][j-1]!=-1) father[i][j]=father[father[i][j-1]][j-1]; } int lca(int a,int b) { if(deepp[a]<deepp[b]) swap(a,b); int i; for(i=0;(1<<i)<=deepp[a];++i); i--; for(int j=i;j>=0;--j) if(deepp[a]-deepp[b]>=(1<<j)) a=father[a][j]; if(a==b) return a; for(int j=i;j>=0;--j) if(father[a][j]!=-1&&father[a][j]!=father[b][j]) { a=father[a][j]; b=father[b][j]; } return father[a][0]; } int main() { freopen("pwalk.in","r",stdin); freopen("pwalk.out","w",stdout); input(); memset(father,-1,sizeof(father)); dis[1]=0; deepp[1]=1; dfs(1); pre_chuli(); for(int i=1;i<=Q;++i) { scanf("%d%d",&p1,&p2); int ance=lca(p1,p2); cout<<dis[p1]+dis[p2]-2*dis[ance]<<endl; } fclose(stdin);fclose(stdout); return 0; }
★★☆ 輸入文件:ThefallingofZLX.in
輸出文件:ThefallingofZLX.out
簡單對比
時間限制:1 s 內存限制:256 MB
正當革命如火如荼,情侶教會日薄西山之時,SOX和FFF的分歧卻愈來愈大,SOX認爲情侶教會不合適的、無限制的秀恩愛和階級歧視值得反對,而FFF認爲一切情侶都該從這個世界上消失。
SOX先發制人,率先接管了全國政權並突襲了FFF,暗殺了FFF的首領,FFF的紅色革命事業遭到了空前的打擊,一些FFF團員積極抵抗,另外一些FFF團員隱居避世,而一些FFF團員則走向極端,參加了一個邪惡組織:詛咒教會
你雖然對SOX下山摘桃子的行爲不滿,但你對邪教更不滿。在對詛咒教會的長期調查中,你發現該組織的操縱者是亡靈巫師ZLX!如今,維護正義的使命降到了你身上!你和其餘的一些遠征軍將士前往ZLX的城堡,卻掉入了ZLX的魔法陷阱--扭曲虛空,扭曲虛空由n個魔法結界空間組成,m條虛空隧道鏈接着它們,你和其餘的遠征軍將士(剛好有n個)分散在魔法結界空間裏,只有會合在一塊兒,大家才能衝破封鎖(扭曲虛空是一顆樹)。如今,你向平行世界的你提出了疑問,若是給出兩我的會合,總共至少須要多少魔法能量?
已知虛空隧道的長度與消耗的魔法能量在數值上相等。
ZLX的末日已經到臨,等到你衝出虛空隧道,親手結果了ZLX吧!
第一行一個正整數N,表明魔法結界空間的個數,一個正整數M,表明虛空隧道的個數
接下來M行,每行三個數u,v,w,表明虛空隧道鏈接的兩個點和虛空隧道的長度
接下來一個正整數Q,表明查詢個數
接下來Q行,每行兩個數u,v表明詢問從u到v須要消耗的魔法能量
Q行,每行一個正整數
6 5 1 2 7 1 3 3 2 4 5 3 5 7 4 6 6 5 3 4 6 3 5 1 4 3 4 2
15 21 10 15 5
對於20%的數據,n<=300,q<=300
對於40%的數據,n<=2000,q<=2000
對於100%的數據,n<=100000,q<=100000,w<=32767,m=n-1
1 #define N 100100 2 #include<iostream> 3 using namespace std; 4 #include<cstdio> 5 #include<cstring> 6 #define Er 20 7 typedef long long ll; 8 ll dis[N]={0}; 9 int deepp[N],father[N][Er],t,n,m,u1,v1,w1,Q; 10 struct Edge{ 11 int v,last,w; 12 }edge[N<<1]; 13 int head[N]; 14 void add_edge(int u,int v,int w) 15 { 16 ++t; 17 edge[t].v=v; 18 edge[t].w=w; 19 edge[t].last=head[u]; 20 head[u]=t; 21 } 22 void input() 23 { 24 scanf("%d%d",&n,&m); 25 for(int i=1;i<=m;++i) 26 { 27 scanf("%d%d%d",&u1,&v1,&w1); 28 add_edge(u1,v1,w1); 29 add_edge(v1,u1,w1); 30 } 31 } 32 void dfs(int k) 33 { 34 for(int l=head[k];l;l=edge[l].last) 35 { 36 if(!deepp[edge[l].v]) 37 { 38 deepp[edge[l].v]=deepp[k]+1; 39 father[edge[l].v][0]=k; 40 dis[edge[l].v]=dis[k]+edge[l].w; 41 dfs(edge[l].v); 42 } 43 } 44 } 45 void pre_chuli() 46 { 47 for(int j=1;(1<<j)<=n;++j) 48 for(int i=1;i<=n;++i) 49 if(father[i][j-1]!=-1) 50 father[i][j]=father[father[i][j-1]][j-1]; 51 } 52 int lca(int a,int b) 53 { 54 if(deepp[a]<deepp[b]) swap(a,b); 55 int i; 56 for(i=0;(1<<i)<=deepp[a];++i); 57 i--; 58 for(int j=i;j>=0;--j) 59 if(deepp[a]-deepp[b]>=(1<<j)) 60 a=father[a][j]; 61 if(a==b) return a; 62 for(int j=i;j>=0;--j) 63 if(father[a][j]!=-1&&father[a][j]!=father[b][j]) 64 { 65 a=father[a][j]; 66 b=father[b][j]; 67 } 68 return father[a][0]; 69 } 70 int main() 71 { 72 freopen("ThefallingofZLX.in","r",stdin); 73 freopen("ThefallingofZLX.out","w",stdout); 74 input(); 75 memset(father,-1,sizeof(father)); 76 dis[1]=0; 77 deepp[1]=1; 78 dfs(1); 79 pre_chuli(); 80 scanf("%d",&Q); 81 for(int i=1;i<=Q;++i) 82 { 83 scanf("%d%d",&u1,&v1); 84 int ance=lca(u1,v1); 85 cout<<dis[u1]+dis[v1]-2*dis[ance]<<endl; 86 } 87 fclose(stdin);fclose(stdout); 88 return 0; 89 }
2013年NOIP全國聯賽提升組
A 國有 n 座城市,編號從 1 到 n,城市之間有 m 條雙向道路。每一條道路對車輛都有重量限制,簡稱限重。如今有 q 輛貨車在運輸貨物,司機們想知道每輛車在不超過車輛限重的狀況下,最多能運多重的貨物。
第一行有兩個用一個空格隔開的整數 n,m,表示 A 國有 n 座城市和 m 條道路。
接下來 m 行每行 3 個整數 x、y、z,每兩個整數之間用一個空格隔開,表示從 x 號城市到 y 號城市有一條限重爲 z 的道路。注意:x 不等於 y,兩座城市之間可能有多條道路。
接下來一行有一個整數 q,表示有 q 輛貨車須要運貨。
接下來 q 行,每行兩個整數 x、y,之間用一個空格隔開,表示一輛貨車須要從 x 城市運輸貨物到 y 城市,注意:x 不等於 y。
輸出共有 q 行,每行一個整數,表示對於每一輛貨車,它的最大載重是多少。若是貨車不能到達目的地,輸出-1。
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
3
-1
3
對於 30%的數據,0 < n < 1,000,0 < m < 10,000,0 < q < 1,000;
對於 60%的數據,0 < n < 1,000,0 < m < 50,000,0 < q < 1,000;
對於 100%的數據,0 < n < 10,000,0 < m < 50,000,0 < q < 30,000,0 ≤ z ≤ 100,000。
/*--------------解析---------------------*/ 拿到這道題,咱們求的是多組兩點間通路上最大的最小邊權,最大生成樹的兩點間最小邊權就知足這個性質,因此就用到到最大生成樹 很容易獲得60分算法 60分算法:(最大生成樹暴力) 先找一個最大生成樹,而後把生成樹單獨放在一個相似生成樹存儲方式的三個數組裏,初始化並查集,而後從最大邊開始作kruskal,每次連邊時,都對問題集合進行掃描,當且僅當這兩個邊聯通且沒有更新過當前問題的答案,就用當前邊權更新。緣由很簡單,這是貪心,首先邊權時降序的,而後這個邊使兩點第一次聯通,那麼這個邊必定是通路上最小的邊。這就是60的算法。可是注意,題目並無說是否是一棵樹,因此它能夠是森林,可是因爲六十分算法原理對於森林這個性質並不依賴,因此,這個60算法不用考慮森林 那麼咱們想一下,這道題時間的瓶頸在哪,首先kruskal是o(m)的,這個不會爆時間,那麼剩下就是從最大生成樹上回答答案所用時間過長。 咱們想一下,若是是在logn時間內回答一個問題,並且是在樹上作的一個算法,尤爲是這個問題具備區間求和的性質,由於想想就知道這是顯然的 f[i→j]:=min(f[i→k],f[k→j]), 因此,咱們想到用樹上倍增算法解決。 100分算法(最大生成樹+樹上倍增): 首先清楚樹上倍增原理:f[i,j]:=f[f[I,j-1],j-1] f[I,j],表示 i向上2^j的節點 同時,設咱們要求的答案g[i,j],即從i向上走到達2^j層的節點所經過路徑上的最小值,轉移方程 g[I,j]:=min(g[f[I,j-1],j-1],g[I,j-1]) 分析一下就是顯然的,g[f[I,j-1],j-1]表示的是i向上2^(j-1)的節點到2^j節點間的最小值,g[I,j-1] 是從i向上走到達2^(j-1)層的節點所經過路徑上的最小值,兩個區間合起來就是當前的區間長度,因此這個方程成立。對於初值,咱們能夠bfs求深度並記錄,與此同時,f[I,0]是父節點,g[I,0]是他向上走一層的邊的長度。而後按照倍增算法模板生成f g數組 求解時,用倍增算法模板便可,只不過有幾個細節 1、 別忘了給ans賦初值 2、 倍增算法永遠是倍增到最近公共祖先的下一層的兩個點,因此最後要比較一下ans與那兩個點的向上走一步的值 3、 記得這是個森林,要用一個數組記一下那個是父節點,我用的是並查集加bool數組,有個細節是不要直接把fa[i]當I的所在樹的根,要get一下,由於並查集的壓縮路徑是在每次get時才更新,當他fa變了,而他未被查詢過,就會致使fa過期了,要從新get一下 4、 在對齊兩個所求節點的層數時,別忘了更新答案 大概就是這些,還有相關代碼具體實現就不贅述了。 哦,對了,提交不要忘了刪除調試用的輸出
1 /* 2 60分代碼:暴力建q棵最大生成樹 3 */ 4 #define N 10008 5 #define M 50007 6 #include<iostream> 7 using namespace std; 8 #include<cstdio> 9 #include<cstring> 10 #include<algorithm> 11 int n,m,q,fa[N],head[N],t=0; 12 struct Edge{ 13 int u,v,w,last; 14 bool operator <(Edge P) 15 const{return w>P.w;} 16 }edge[M<<1]; 17 int read() 18 { 19 int ret=0,ff=1; 20 char s=getchar(); 21 while(s<'0'||s>'9') 22 { 23 if(s=='-') ff=-1; 24 s=getchar(); 25 } 26 while(s>='0'&&s<='9') 27 { 28 ret=ret*10+s-'0'; 29 s=getchar(); 30 } 31 return ret; 32 } 33 inline void add_edge(int u,int v,int w) 34 { 35 ++t; 36 edge[t].u=u; 37 edge[t].v=v; 38 edge[t].w=w; 39 edge[t].last=head[u]; 40 head[u]=t; 41 } 42 inline void inpu() 43 { 44 n=read();m=read(); 45 int x,y,z; 46 for(int i=1;i<=m;++i) 47 { 48 x=read();y=read();z=read(); 49 add_edge(x,y,z); 50 } 51 } 52 int find(int x) 53 { 54 return (fa[x]==x)?x:fa[x]=find(fa[x]); 55 } 56 int main() 57 { 58 freopen("truck.in","r",stdin); 59 freopen("truck.out","w",stdout); 60 inpu(); 61 sort(edge+1,edge+t+1); 62 q=read(); 63 int x,y; 64 for(int i=1;i<=q;++i) 65 { 66 x=read();y=read(); 67 for(int i=1;i<=n;++i) fa[i]=i; 68 bool flag=false; 69 for(int i=1;i<=t;++i) 70 { 71 int x1=find(edge[i].u); 72 int y1=find(edge[i].v); 73 if(x1!=y1) 74 { 75 fa[y1]=x1; 76 } 77 if(find(x)==find(y)) 78 { 79 printf("%d\n",edge[i].w); 80 flag=true; 81 break; 82 } 83 } 84 if(!flag) printf("-1\n"); 85 } 86 fclose(stdin); 87 fclose(stdout); 88 return 0; 89 }
1 #define N 10010 2 #define inf 10000800 3 #include<cstdio> 4 #define M 50002 5 #define D 18 6 #include<cstring> 7 #include<algorithm> 8 #include<cstdio> 9 using namespace std; 10 int n,m,q,fa[N],t=0; 11 struct EEdge{ 12 int u,v,w; 13 bool operator <(EEdge P) 14 const{return w>P.w;} 15 }edge1[M]; 16 struct Edge{ 17 int v,w,last; 18 }e[N]; 19 int dis[N][D+1],fath[N][D+1],dep[N],head[N]; 20 int read() 21 { 22 int ret=0,ff=1; 23 char s=getchar(); 24 while(s<'0'||s>'9') 25 { 26 if(s=='-') ff=-1; 27 s=getchar(); 28 } 29 while(s>='0'&&s<='9') 30 { 31 ret=ret*10+s-'0'; 32 s=getchar(); 33 } 34 return ret*ff; 35 } 36 void inpu() 37 { 38 n=read();m=read(); 39 for(int i=1;i<=m;++i) 40 { 41 edge1[i].u=read(); 42 edge1[i].v=read(); 43 edge1[i].w=read(); 44 } 45 } 46 int fi(int x) 47 { 48 return (fa[x]==x)?x:fa[x]=fi(fa[x]); 49 } 50 void add_edge(int u,int v,int w) 51 { 52 ++t; 53 e[t].v=v; 54 e[t].w=w; 55 e[t].last=head[u]; 56 head[u]=t; 57 } 58 void ddkruskal() 59 { 60 for(int i=1;i<=n;++i) fa[i]=i; 61 sort(edge1+1,edge1+m+1); 62 int tsum=0; 63 for(int i=1;i<=m;++i) 64 { 65 int x1=fi(edge1[i].u); 66 int x2=fi(edge1[i].v); 67 if(x1!=x2) 68 { 69 tsum++; 70 fa[x2]=x1; 71 add_edge(edge1[i].u,edge1[i].v,edge1[i].w); 72 add_edge(edge1[i].v,edge1[i].u,edge1[i].w); 73 if(tsum==n-1) break; 74 } 75 } 76 } 77 void dfs(int k) 78 { 79 for(int l=head[k];l;l=e[l].last) 80 { 81 if(!dep[e[l].v]) 82 { 83 dep[e[l].v]=dep[k]+1; 84 fath[e[l].v][0]=k; 85 dis[e[l].v][0]=e[l].w; 86 dfs(e[l].v); 87 } 88 } 89 } 90 void init() 91 { 92 for(int j=1;j<=D;++j) 93 for(int i=1;i<=n;++i) 94 { 95 fath[i][j]=fath[fath[i][j-1]][j-1]; 96 dis[i][j]=min(dis[i][j-1],dis[fath[i][j-1]][j-1]); 97 } 98 } 99 int lca(int a,int b) 100 { 101 int ans=inf; 102 if(dep[a]<dep[b]) swap(a,b); 103 for(int j=D;j>=0;--j) 104 { 105 if(dep[a]-(1<<j)>=dep[b]) 106 { 107 ans=min(ans,dis[a][j]); 108 a=fath[a][j]; 109 } 110 } 111 if(a==b) return ans; 112 for(int j=D;j>=0;--j) 113 { 114 if(fath[a][j]!=fath[b][j]) 115 { 116 ans=min(ans,min(dis[a][j],dis[b][j])); 117 a=fath[a][j]; 118 b=fath[b][j]; 119 } 120 } 121 ans=min(ans,min(dis[a][0],dis[b][0])); 122 return ans; 123 } 124 int main() 125 { 126 freopen("truck.in","r",stdin); 127 freopen("truck.out","w",stdout); 128 inpu(); 129 ddkruskal(); 130 q=read(); 131 int x,y; 132 for(int i=1;i<=n;++i) 133 { 134 if(!dep[i]) 135 { 136 dep[i]=1; 137 fath[i][0]=i; 138 dis[i][0]=inf; 139 dfs(i); 140 } 141 } 142 init(); 143 for(int i=1;i<=q;++i) 144 { 145 x=read();y=read(); 146 if(fi(x)!=fi(y)) printf("-1\n"); 147 else printf("%d\n",lca(x,y)); 148 } 149 fclose(stdin); 150 fclose(stdout); 151 return 0; 152 }