2017/11/08 胡策 T3
阿新 • • 發佈:2018-05-15
tchar pan esp filesize contain emp inline code 樹上倍增
出題人:ISA
一個長為 n 的鏈,點權分別為 1 ~ n,最左邊的點權為 n,最右邊的點權為 1,每個點分別向左邊和右邊第一個比它大的點連長為 1 的無向邊,問任意兩點的最短路徑。1 <= n <= 100000。
考慮連邊的性質,兩點的最短路徑一定是點權遞增或先增後減,所以相當於由點權小的向點權大的連有向邊,每次詢問時兩點同時往上跳,跳到同一個點終止。設向左連的邊構成左樹,向右連的構成右樹,則兩點可能的終點只有三個:左樹 lca、右樹 lca、左樹和右樹到根路徑的交點(即兩點所夾區間最大值的位置)。
考慮怎樣用倍增來解決,利用每個點向第一個比它大的點連邊的性質,若 x 的目標結點是 y,x 連接的兩個點分別為 a 和 b,且 x < a < b < y,則跳 b 肯定比跳 a 優,所以可以使每個點向它兩條邊中較大點連邊建出優勢樹,在優勢樹上倍增,跳到下一個點就要大於 y 時停止,可利用性質證明這時剩下的邊一定是都在左樹或都在右樹上,直接用深度相減得出答案。
例如序列:
10 | 8 | 4 | 3 | 2 | 5 | 6 | 7 | 9 | 1 |
---|
藍邊表示左樹,紫邊表示右樹:
紅邊表示優勢樹:
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> 9std#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 }
極限數據生成:隨機一個排列,分成大概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