1. 程式人生 > >2017/11/08 胡策 T3

2017/11/08 胡策 T3

tchar pan esp filesize contain emp inline code 樹上倍增

一個長為 n 的鏈,點權分別為 1 ~ n,最左邊的點權為 n,最右邊的點權為 1,每個點分別向左邊和右邊第一個比它大的點連長為 1 的無向邊,問任意兩點的最短路徑。1 <= n <= 100000。

  考慮連邊的性質,兩點的最短路徑一定是點權遞增或先增後減,所以相當於由點權小的向點權大的連有向邊,每次詢問時兩點同時往上跳,跳到同一個點終止。設向左連的邊構成左樹,向右連的構成右樹,則兩點可能的終點只有三個:左樹 lca、右樹 lca、左樹和右樹到根路徑的交點(即兩點所夾區間最大值的位置)。

  考慮怎樣用倍增來解決,利用每個點向第一個比它大的點連邊的性質,若 x 的目標結點是 y,x 連接的兩個點分別為 a 和 b,且 x < a < b < y,則跳 b 肯定比跳 a 優,所以可以使每個點向它兩條邊中較大點連邊建出優勢樹,在優勢樹上倍增,跳到下一個點就要大於 y 時停止,可利用性質證明這時剩下的邊一定是都在左樹或都在右樹上,直接用深度相減得出答案。

  例如序列:

10843256791

  藍邊表示左樹,紫邊表示右樹:

技術分享圖片

  紅邊表示優勢樹:

技術分享圖片 技術分享圖片
  1 #include <bits/stdc++.h>
  2 
  3 #define x first
  4 #define y second
  5 #define pb push_back
  6 #define mp make_pair
  7 #define vi vector<int>
  8 #define pr pair<int,int>
  9
#define SZ(S) int(S.size()) 10 #define REP(i,a,b) for(int i=a;i<b;++i) 11 #define FOR(i,a,b) for(int i=a;i<=b;++i) 12 #define FORD(i,b,a) for(int i=b;i>=a;--i) 13 #define CLR(A,x) memset(A,x,sizeof(A)) 14 #define ALL(S) S.begin(),S.end() 15 16 #define OUT(a,l,r) cout<<#a": ";FOR(i,l,r)cout<<a[i]<<" ";cout<<endl 17
#define PRT(a) cout<<"--> "#a" "<<a<<endl 18 19 using namespace std; 20 typedef long long ll; 21 22 const int N=100005,M=18,INF=0x3f3f3f3f; 23 const ll P=1e9+7; 24 25 template<typename T> 26 inline void read(T& x,int f=1,char s=getchar()) { 27 for(x=0;s>9||s<0;s=getchar()) if(s==-) f=-1; 28 while(s<=9&&s>=0) x=x*10+s-0,s=getchar();x*=f; 29 } 30 31 set<int> s; 32 int n,m; 33 int t[N<<2]; 34 int l[N],r[N]; 35 int a[N],rk[N]; 36 int depl[N],depr[N]; 37 int f[N][M]; 38 39 #define ne (o<<1) 40 #define mid ((l+r)>>1) 41 void build(int o,int l,int r) { 42 if(l==r) {t[o]=a[l];return;} 43 build(ne,l,mid),build(ne|1,mid+1,r); 44 t[o]=max(t[ne],t[ne|1]); 45 } 46 47 int qmax(int o,int l,int r,int L,int R,int ret=0) { 48 if(L<=l&&r<=R) return t[o]; 49 if(L<=mid) ret=max(ret,qmax(ne,l,mid,L,R)); 50 if(R>mid) ret=max(ret,qmax(ne|1,mid+1,r,L,R)); 51 return ret; 52 } 53 54 #define IT set<int>::iterator 55 void pre() { 56 s.insert(1),s.insert(n); 57 FORD(i,n-2,1) { 58 int x=rk[i]; 59 IT it=s.insert(x).x; 60 IT it1=it;it1--; 61 IT it2=it;it2++; 62 l[x]=*it1; 63 r[x]=*it2; 64 } 65 l[n]=1; 66 FOR(i,1,n) depl[i]=depl[l[i]]+1; 67 FORD(i,n,1) depr[i]=depr[r[i]]+1; 68 FORD(i,n-2,1) { 69 int x=rk[i]; 70 if(a[l[x]]>=a[r[x]]) f[x][0]=l[x]; 71 else f[x][0]=r[x]; 72 REP(j,1,M) f[x][j]=f[f[x][j-1]][j-1]; 73 } 74 f[n][0]=1; 75 } 76 77 int dis(int x,int y,int *l,int *dep) { 78 if(x==y) return 0; 79 if(l[x]==y) return 1; 80 81 int ret=0; 82 FORD(i,M-1,0) { 83 int xx=f[x][i]; 84 if(xx==0) continue; 85 if(xx==y) return ret+(1<<i); 86 if(l[xx]==y) return ret+(1<<i)+1; 87 if(dep[y]<dep[l[xx]]) x=xx,ret+=(1<<i); 88 } 89 return INF; 90 } 91 92 int main() { 93 int x,y,z; 94 read(n),read(m); 95 FOR(i,1,n) read(a[i]),rk[a[i]]=i; 96 build(1,1,n); 97 pre(); 98 FOR(i,1,m) { 99 read(x),read(y); 100 int ans=INF; 101 z=rk[qmax(1,1,n,x,y)]; 102 ans=min(ans,dis(x,z,r,depr)+dis(y,z,l,depl)); 103 104 if(l[z]) ans=min(ans,dis(x,l[z],l,depl)+dis(y,l[z],l,depl)); 105 if(r[z]) ans=min(ans,dis(x,r[z],r,depr)+dis(y,r[z],r,depr)); 106 printf("%d\n",ans); 107 } 108 return 0; 109 }
std

極限數據生成:隨機一個排列,分成大概20段,每段內排序。

技術分享圖片
 1 #include <bits/stdc++.h>
 2 
 3 #define x first
 4 #define y second
 5 #define pb push_back
 6 #define mp make_pair
 7 #define vi vector<int>
 8 #define pr pair<int,int>
 9 #define SZ(S) int(S.size())
10 #define REP(i,a,b) for(int i=a;i<b;++i)
11 #define FOR(i,a,b) for(int i=a;i<=b;++i)
12 #define FORD(i,b,a) for(int i=b;i>=a;--i)
13 #define CLR(A,x) memset(A,x,sizeof(A))
14 #define ALL(S) S.begin(),S.end()
15 
16 #define OUT(a,l,r) cout<<#a": ";FOR(i,l,r)cout<<a[i]<<" ";cout<<endl
17 #define PRT(a) cout<<"--> "#a" "<<a<<endl
18 
19 using namespace std;
20 typedef long long ll;
21 
22 const int N=100005,M=20,INF=0x3f3f3f3f;
23 const ll P=1e9+7;
24 
25 template<typename T>
26 inline void read(T& x,int f=1,char s=getchar()) {
27     for(x=0;s>9||s<0;s=getchar()) if(s==-) f=-1; 
28     while(s<=9&&s>=0) x=x*10+s-0,s=getchar();x*=f;
29 }
30 
31 string pro="";
32 void add(string& s,int id) {
33     if(id>=10) {
34         s+=char(id/10+0);
35         s+=char(id%10+0);
36     }
37     else {
38         s+=char(id+0);
39     }
40 }
41 
42 void gen_i(int id) {
43     string str="data.exe > data\\";
44     str+=pro;
45     add(str,id);
46     str+=".in";
47     cout<<str<<endl;
48     system(str.c_str());
49 }
50 
51 void gen_o(int id) {
52     string str="std.exe < data\\";
53     str+=pro;
54     add(str,id);
55     str+=".in > data\\";
56     str+=pro;
57     add(str,id);
58     str+=".out";
59     cout<<str<<endl;
60     system(str.c_str());
61 }
62 
63 int main() {
64     int l=1;
65     int r=10;
66     
67     FOR(i,l,r) gen_i(i);
68     FOR(i,l,r) gen_o(i);
69 }
data


出題人:ISA

2017/11/08 胡策 T3