1. 程式人生 > >51nod1766 樹上的最遠點對

51nod1766 樹上的最遠點對

pan std none blog 歐拉 mage ace 第一個 print

n<=1e5個點的樹有邊權,m個詢問,每次問max dis(i,j) a<=i<=b,c<=j<=d。

結論:一個區間的最遠點對,要麽是其左半區間的最遠點對,要麽是其右半區間的最遠點對,要麽是左右半區間最遠點對的四個點的互相組合之一。如下圖:

技術分享

兩個集合最遠點對分別是A-B,A並B的最遠點對是紅A-藍B。

簡單證明:一個點到一個點集的最長路徑一定是該點到 該點集最遠點對這對點的某一點 這樣的一條路徑。

技術分享

比如紅點這個集合,從藍色點到紅色點集的最長路。如果X到達A到B這條鏈遇到的第一個點是A,那麽最遠就是X到B;如果X到達A到B這條鏈遇到的第一個點是B,那麽最遠就是X到A。如果是像上圖這種情況,那麽最遠點對就是X走到B或X走到A。上圖的情況中,設X到左上方點距離a,x到AB鏈遇到的第一個點C距離b,A到C距離c,B到C距離d,C到右下方的點距離e。可以通過不等式簡單加減證明。

所以就用個線段樹維護即可,最後把查到兩個區間做合並。註意最後一次合並和線段樹的合並不一樣!!最後的查詢問的是兩個區間裏的點配對,不能把兩個點選在同個區間!!

這題時限比較緊,建議不用倍增求lca,這裏用了歐拉序加rmq。

技術分享
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<cstdlib>
  5 #include<cmath>
  6 //#include<iostream>
  7 using namespace
std; 8 9 struct Mes 10 { 11 int s,t,v; 12 }; 13 int n; 14 #define maxn 100011 15 struct Edge{int to,next,v;}edge[maxn<<1];int first[maxn],le=2; 16 void in(int x,int y,int v) {Edge &e=edge[le];e.to=y;e.v=v;e.next=first[x];first[x]=le++;} 17 void insert(int x,int y,int v) {in(x,y,v);in
(y,x,v);} 18 int dep[maxn],pos[maxn]; int ll=0,Log[maxn<<1],rmq[maxn<<1][22]; 19 void dfs(int x,int f) 20 { 21 // cout<<x<<endl; 22 rmq[++ll][0]=x;pos[x]=ll; 23 for (int i=first[x];i;i=edge[i].next) 24 { 25 const Edge &e=edge[i];if (e.to==f) continue; 26 dep[e.to]=dep[x]+e.v; 27 dfs(e.to,x); 28 rmq[++ll][0]=x; 29 } 30 } 31 void pre() 32 { 33 dep[0]=dep[1]=0;dfs(1,0); 34 Log[0]=-1;for (int i=1;i<=ll;i++) Log[i]=Log[i>>1]+1; 35 for (int j=1;j<=20;j++) 36 for (int i=1,to=ll-(1<<j)+1;i<=to;i++) 37 if (dep[rmq[i][j-1]]<dep[rmq[i+(1<<(j-1))][j-1]]) 38 rmq[i][j]=rmq[i][j-1]; 39 else rmq[i][j]=rmq[i+(1<<(j-1))][j-1]; 40 } 41 int lca(int x,int y) 42 { 43 x=pos[x],y=pos[y];if (x>y) {int t=x;x=y;y=t;} 44 int l=Log[y-x+1]; 45 return dep[rmq[x][l]]<dep[rmq[y-(1<<l)+1][l]]?rmq[x][l]:rmq[y-(1<<l)+1][l]; 46 } 47 int dis(int x,int y) 48 { 49 int l=lca(x,y); 50 return dep[x]+dep[y]-2*dep[l]; 51 } 52 Mes combine(Mes a,Mes b,bool flag) 53 { 54 Mes c;c.v=-1;int tmp; 55 if ((tmp=dis(a.s,b.s))>c.v) 56 { 57 c.v=tmp;c.s=a.s;c.t=b.s; 58 } 59 if ((tmp=dis(a.s,b.t))>c.v) 60 { 61 c.v=tmp;c.s=a.s;c.t=b.t; 62 } 63 if ((tmp=dis(a.t,b.s))>c.v) 64 { 65 c.v=tmp;c.s=a.t;c.t=b.s; 66 } 67 if ((tmp=dis(a.t,b.t))>c.v) 68 { 69 c.v=tmp;c.s=a.t;c.t=b.t; 70 } 71 if (flag) 72 { 73 if (a.v>b.v && a.v>c.v) c=a; 74 else if (b.v>a.v && b.v>c.v) c=b; 75 } 76 return c; 77 } 78 struct SMT 79 { 80 struct Node 81 { 82 Mes m; 83 int l,r; 84 int ls,rs; 85 }a[maxn<<1]; 86 int size; 87 SMT() {size=0;} 88 void up(int x) 89 { 90 const int &p=a[x].ls,&q=a[x].rs; 91 a[x].m=combine(a[p].m,a[q].m,1); 92 } 93 void build(int &x,int L,int R) 94 { 95 x=++size; 96 a[x].l=L;a[x].r=R; 97 if (L==R) 98 { 99 a[x].ls=a[x].rs=0; 100 a[x].m.s=L;a[x].m.t=R; 101 a[x].m.v=0; 102 return; 103 } 104 const int mid=(L+R)>>1; 105 build(a[x].ls,L,mid); 106 build(a[x].rs,mid+1,R); 107 up(x); 108 // cout<<a[x].l<<‘~‘<<a[x].r<<‘ ‘<<a[x].m.s<<‘ ‘<<a[x].m.t<<‘ ‘<<a[x].m.v<<endl; 109 } 110 void build() 111 { 112 int x; 113 build(x,1,n); 114 } 115 int ql,qr; 116 Mes query(int x) 117 { 118 if (ql<=a[x].l && a[x].r<=qr) return a[x].m; 119 else 120 { 121 const int mid=(a[x].l+a[x].r)>>1; 122 bool flag=0;Mes ans; 123 if (ql<=mid) ans=query(a[x].ls),flag=1; 124 if (qr> mid) ans=flag?combine(ans,query(a[x].rs),1):query(a[x].rs); 125 return ans; 126 } 127 } 128 Mes query(int L,int R) 129 { 130 ql=L;qr=R; 131 return query(1); 132 } 133 }t; 134 int m,x,y,v,z; 135 int main() 136 { 137 scanf("%d",&n); 138 for (int i=1;i<n;i++) 139 { 140 scanf("%d%d%d",&x,&y,&v); 141 insert(x,y,v); 142 } 143 // cout<<":)"; 144 pre(); 145 // cout<<":)"; 146 t.build(); 147 // cout<<":)"; 148 scanf("%d",&m); 149 // cout<<m<<endl; 150 while (m--) 151 { 152 scanf("%d%d%d%d",&x,&y,&v,&z); 153 Mes ans=combine(t.query(x,y),t.query(v,z),0); 154 printf("%d\n",ans.v); 155 } 156 return 0; 157 }
View Code

51nod1766 樹上的最遠點對