1. 程式人生 > >[51nod] 1766 樹上的最遠點對

[51nod] 1766 樹上的最遠點對

2-2 然而 移植 list pac put href || 感謝

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 樹上的最遠點對