[51nod] 1766 樹上的最遠點對
阿新 • • 發佈:2017-10-08
2-2 然而 移植 list pac put href || 感謝
(PS 建議使用讀入優化) Input
1766 樹上的最遠點對
基準時間限制:3 秒 空間限制:524288 KB 分值: 80 難度:5級算法題
n個點被n-1條邊連接成了一顆樹,給出a~b和c~d兩個區間,表示點的標號請你求出兩個區間內各選一點之間的最大距離,即你需要求出max{dis(i,j) |a<=i<=b,c<=j<=d}(PS 建議使用讀入優化) Input
第一行一個數字 n n<=100000。 第二行到第n行每行三個數字描述路的情況, x,y,z (1<=x,y<=n,1<=z<=10000)表示x和y之間有一條長度為z的路。 第n+1行一個數字m,表示詢問次數 m<=100000。 接下來m行,每行四個數a,b,c,d。Output
共m行,表示每次詢問的最遠距離
Input示例
5
1 2 1
2 3 2
1 4 3
4 5 4
1
2 3 4 5
Output示例
10
Analysis
洛谷秋令營講解過的題目,因此並沒有用很多時間進行深刻的思考
基本構架:線段樹,用於處理區間詢問
首先我們有A B兩個點集,從A B中各取一個點以組成最遠點對,求出其距離
首先可以有這一個結論:最後的最遠點對的點,在A中的,必然也是A中最遠點對的其中一個點
因此線段樹維護每個區間的最遠點對,當區間合並的時候取他們各自的最遠點對暴力取優即可
(百度一發題解,有人指出最遠點對的合並與樹的直徑的合並具有相似性,因此得出上面的結論)
(但是本蒟蒻很迷啊)
好,接下來談實現
1. 線段樹!
首先線段樹基本框架沒有問題,我們需要實現一個函數:合並(merge)
這裏推薦在單點區間內把最遠點對的兩個點都設成自己(第一個坑)
不然合並的時候爆炸(我將不存在的點設成了-1結果qwq)
最後的答案要求從A B各取一個點,所以合並函數還需要註意:線段樹內的合並可以從單個集合中取點對,而最終答案不行
2. 求距離!
要求求出最近公共祖先(然後瞎搞)
倍增LCA,TLE最後6個點
雖然我沒怎麽卡常數而且寫的非常粗糙(比如沒有記憶化每次都要重新求)
但是顯然這是算法問題
所以找CCZ求得了一個O(1)LCA的方案
orz ccz!
首先求出當前樹的歐拉序(不同於DFS序的是,這裏的歐拉序要求包括每一次進入的結點)
然後對於這份DFS序,我們要做的就是:求出區間(以U V的隨便哪個DFN值做區間端點)的最小值(這裏的區間保存的是深度Depth)所對應的那個點
顯然,那個點就是U V的LCA
而使用ST表的話可以做到O(1)查詢
qwq 然而我沒學ST表啊 qwq
所以最後跑去看了qt666的博客
qwq (其實代碼中的ST表代碼是無縫移植qt666的,表示感謝!)
(找個時間還是要重寫一遍的,一是不大好無縫移植,趁早學會重造比較好,二是各種調試代碼太多)
(敲這道題的時候我居然沒有重寫)
Code
1 #include<stdio.h> 2 #include<iostream> 3 #define maxn 1000000 4 #define lc (rt<<1) 5 #define rc (rt<<1|1) 6 #define mid ((L+R)/2) 7 using namespace std; 8 9 int dfn[maxn],dfnn[maxn],TIM,line[maxn],chain[maxn],sum[maxn]; 10 int pre[maxn],pre2[maxn],ST[maxn][30]; 11 int fa[maxn][20],ro[maxn][20],depth[maxn],n,m; 12 13 struct edge{ int from,u,v,len; }e[maxn]; 14 int tot,first[maxn]; 15 void insert(int u,int v,int len){ tot++; e[tot].from = first[u], e[tot].u = u , e[tot].v = v , e[tot].len = len, first[u] = tot; } 16 17 void dfs(int now){ 18 dfn[now] = ++TIM; 19 line[TIM] = -depth[now]; 20 chain[TIM] = now; 21 for(int i = first[now];i;i = e[i].from){ 22 int v = e[i].v; 23 if(v != fa[now][0]){ 24 sum[v] = sum[now]+e[i].len; 25 depth[v] = depth[now]+1; 26 fa[v][0] = now; 27 // ro[v][0] = e[i].len; 28 dfs(v); 29 line[++TIM] = -depth[now]; 30 chain[TIM] = now; 31 } 32 } 33 } 34 void Init(){ 35 for(int i = 1;i <= 18;i++) 36 for(int j = 1;j <= n;j++) 37 fa[j][i] = fa[fa[j][i-1]][i-1], 38 ro[j][i] = ro[fa[j][i-1]][i-1]+ro[j][i-1]; 39 } 40 41 void makeST() 42 { 43 pre[0]=1;for(int i=1;i<=20;i++) pre[i]=pre[i-1]<<1; 44 pre2[0]=-1;for(int i=1;i<=TIM;i++) pre2[i]=pre2[i>>1]+1; 45 for(int i=1;i<=TIM;i++) ST[i][0]=i; 46 for(int j=1;j<=20;j++) 47 for(int i=1;i<=TIM;i++){ 48 if(i+pre[j]-1<=TIM){ 49 int x1=ST[i][j-1],x2=ST[i+pre[j-1]][j-1]; 50 if(line[x1]>line[x2]) ST[i][j]=x1; 51 else ST[i][j]=x2; 52 } 53 } 54 }int queryST(int l,int r) 55 { 56 l = dfn[l],r = dfn[r]; 57 if(l > r) swap(l,r); 58 // printf("query:[%d , %d]\n",l,r); 59 if(l==r)return chain[l]; 60 int x=pre2[r-l+1]; 61 int x1=ST[l][x],x2=ST[r-pre[x]+1][x]; 62 return line[x1]>line[x2]?chain[x1]:chain[x2]; 63 } 64 65 int getdis(int u,int v){ 66 if(depth[u] < depth[v]) swap(u,v); 67 int anc = queryST(u,v); 68 if(anc == v) return sum[u]-sum[anc]; 69 else return sum[u]+sum[v]-sum[anc]*2; 70 /*int ret = 0; 71 if(depth[u] < depth[v]) swap(u,v); 72 for(int i = 18;i >= 0;i--) 73 if(depth[fa[u][i]] >= depth[v]) 74 ret += ro[u][i], 75 u = fa[u][i]; 76 if(u == v) return ret; 77 for(int i = 18;i >= 0;i--) 78 if(fa[u][i] != fa[v][i]) 79 ret += ro[u][i]+ro[v][i], 80 u = fa[u][i],v = fa[v][i]; 81 return ret + ro[u][0] + ro[v][0];*/ 82 } 83 struct node{ int A,B; node(){A = B = -1;}}Tree[maxn*4]; 84 node merge(node a,node b,int mode){ 85 node tmp; 86 // printf("What I get: a.A%d a.B%d b.A%d b.B%d\n",a.A,a.B,b.A,b.B); 87 int dis = -1; 88 if(a.A > 0 && a.B > 0 && mode){ 89 int cnt = getdis(a.A,a.B); 90 if(cnt > dis) dis = cnt,tmp.A = a.A,tmp.B = a.B; 91 }if(a.A > 0 && b.A > 0){ 92 int cnt = getdis(a.A,b.A); 93 if(cnt > dis) dis = cnt,tmp.A = a.A,tmp.B = b.A; 94 }if(a.A > 0 && b.B > 0){ 95 int cnt = getdis(a.A,b.B); 96 if(cnt > dis) dis = cnt,tmp.A = a.A,tmp.B = b.B; 97 }if(a.B > 0 && b.A > 0){ 98 int cnt = getdis(a.B,b.A); 99 if(cnt > dis) dis = cnt,tmp.A = a.B,tmp.B = b.A; 100 }if(a.B > 0 && b.B > 0){ 101 int cnt = getdis(a.B,b.B); 102 if(cnt > dis) dis = cnt,tmp.A = a.B,tmp.B = b.B; 103 }if(b.A > 0 && b.B > 0 && mode){ 104 int cnt = getdis(b.A,b.B); 105 if(cnt > dis) dis = cnt,tmp.A = b.A,tmp.B = b.B; 106 // cout << "Who visit me qwq?" << endl; 107 } 108 // cout << "dis: " << dis << endl; 109 110 return tmp; 111 } 112 113 void build(int rt,int L,int R){ 114 if(L == R) Tree[rt].A = L,Tree[rt].B = L; 115 else{ 116 build(lc,L,mid); 117 build(rc,mid+1,R); 118 119 Tree[rt] = merge(Tree[lc],Tree[rc],1); 120 } 121 // printf("#%d: L%d R%d A%d B%d\n",rt,L,R,Tree[rt].A,Tree[rt].B); 122 } 123 124 node query(int rt,int L,int R,int qL,int qR){ 125 if(qL <= L && R <= qR) return Tree[rt]; 126 else{ 127 node tmp; 128 if(qL <= mid) tmp = merge(tmp,query(lc,L,mid,qL,qR),1); 129 if(qR > mid) tmp = merge(tmp,query(rc,mid+1,R,qL,qR),1); 130 // printf("tmp now is: %d %d\n",tmp.A,tmp.B); 131 return tmp; 132 } 133 } 134 135 int read(){ 136 int ret = 0; char ctr = getchar(); 137 while(ctr < ‘0‘ || ctr > ‘9‘) ctr = getchar(); 138 while(ctr >= ‘0‘ && ctr <= ‘9‘) ret = ret*10+ctr-‘0‘,ctr = getchar(); 139 return ret; 140 } 141 142 int main(){ 143 // scanf("%d",&n); 144 n = read(); 145 for(int i = 1;i < n;i++){ 146 int x,y,z; //scanf("%d%d%d",&x,&y,&z); 147 x = read(),y = read(),z = read(); 148 insert(x,y,z); insert(y,x,z); 149 }depth[1] = 1; dfs(1); Init(); 150 makeST(); 151 // printf("dis(1,3) %d\n",getdis(1,3)); 152 // scanf("%d",&m); 153 m = read(); 154 // for(int i = 0;i <= TIM;i++){ 155 // for(int j = 0;j <= 9;j++) 156 //// printf("%d ",ST[i][j]); 157 // cout << endl; 158 // } 159 // for(int i = 0;i <= TIM;i++) printf("%d ",line[i]); cout << endl; 160 // for(int i = 0;i <= TIM;i++) printf("%d ",chain[i]); 161 // printf("LCA %d dis(3,4) = %d sum3 %d sum4 %d\n",queryST(3,4),getdis(3,4),sum[3],sum[4]); 162 // printf("LCA of :%d %d = %d\n",1,4,query(1,4)); 163 build(1,1,n); 164 while(m--){ 165 int a,b,c,d; 166 // scanf("%d%d%d%d",&a,&b,&c,&d); 167 a = read(),b = read(),c = read(),d = read(); 168 // cout << "AAA"; 169 node ans = merge(query(1,1,n,a,b),query(1,1,n,c,d),0); 170 // cout << "AAA"; 171 // cout << "Great" << ans.A << ans.B << endl; 172 printf("%d\n",getdis(ans.A,ans.B)); 173 } 174 175 // for(int i = 0;i <= 20;i++) 176 // printf("#%d: %d %d\n",i,Tree[i].A,Tree[i].B); 177 return 0; 178 }qwq
[51nod] 1766 樹上的最遠點對