一个长为 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> 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
原文地址:https://www.cnblogs.com/milky-w/p/9038365.html
时间: 2024-10-11 16:17:07