如此显然的线段树,我又瞎了眼了
事实上跟以前的奇袭很像.......
只要满足公式maxn-minn(权值)==r-l即可
所以可以考虑建两颗树,一棵节点维护位置,一棵权值,
每次从一棵树树上查询信息,如果满足公式就停止,不然两颗树不断扩展区间
当然也可以用ST啦(查询O(1)优于线段树)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<string> 6 #include<set> 7 #include<map> 8 #include<vector> 9 #include<cmath> 10 #define int long long 11 #define MAXN 100101 12 using namespace std; 13 char buffer[1<<20|1],*S,*T; 14 #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,1<<20|1,stdin),S==T))?EOF:*S++) 15 int read() 16 { 17 int x=0;char c=getchar(); 18 while(c<'0'||c>'9')c=getchar(); 19 while(c>='0'&&c<='9') 20 { 21 x=(x<<1)+(x<<3)+(c^48); 22 c=getchar(); 23 } 24 return x; 25 } 26 int a[MAXN]; 27 int maxn,minn; 28 int n,m;int binn[MAXN]; 29 int f[21][MAXN];int f_min[21][MAXN];//区间极值的最小位置,最大位置 30 int wei[21][MAXN];int wei_min[21][MAXN]; 31 void work() 32 { 33 int t=log(n)/log(2); 34 for(int j=1;j<=t;++j) 35 { 36 for(int i=1;i<=(n+1-binn[j]);++i) 37 { 38 f[j][i]=max(f[j-1][i],f[j-1][i+binn[j-1]]); 39 f_min[j][i]=min(f_min[j-1][i],f_min[j-1][i+binn[j-1]]); 40 wei[j][i]=max(wei[j-1][i],wei[j-1][i+binn[j-1]]); 41 wei_min[j][i]=min(wei_min[j-1][i],wei_min[j-1][i+binn[j-1]]); 42 } 43 } 44 } 45 int maxn_wei,minn_wei; 46 void RMB(int l,int r) 47 { 48 int t=log(r-l+1)/log(2); 49 maxn_wei=max(f[t][l],f[t][r+1-binn[t]]); 50 minn_wei=min(f_min[t][l],f_min[t][r+1-binn[t]]); 51 return ; 52 } 53 54 void RMB_wei(int l,int r) 55 { 56 int t=log(r-l+1)/log(2); 57 maxn=max(wei[t][l],wei[t][r+1-binn[t]]); 58 minn=min(wei_min[t][l],wei_min[t][r+1-binn[t]]); 59 return ; 60 } 61 signed main() 62 { 63 n=read(); 64 for(int i=1;i<=n;++i) 65 { 66 a[i]=read(); 67 f[0][a[i]]=i;f_min[0][a[i]]=i; 68 wei[0][i]=a[i];wei_min[0][i]=a[i]; 69 } 70 binn[0]=1; 71 for(int i=1;i<=20;++i)binn[i]=(binn[i-1]<<1); 72 work(); 73 m=read(); 74 for(int i=1;i<=m;++i) 75 { 76 int l,r; 77 l=read();r=read(); 78 maxn=0;minn=0x7ffffffff;maxn_wei=r;minn_wei=l; 79 while(maxn-minn!=maxn_wei-minn_wei) 80 { 81 RMB_wei(minn_wei,maxn_wei); 82 RMB(minn,maxn); 83 } 84 printf("%lld %lld ",minn_wei,maxn_wei); 85 } 86 }
100分:
%%%%%skyh 分块思想碾爆tarjan正解
因为每次区间不断扩展可能会扩展好多边,
那么我们把区间分块,这样预处理出块与块的答案
在实际查询中如果发现当前查询区间大于块的区间,那就可以判断是否用块跳跃
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<string> 6 #include<set> 7 #include<map> 8 #include<vector> 9 #include<cmath> 10 #define int long long 11 #define MAXN 100101 12 using namespace std; 13 int kuan[MAXN];int belong[MAXN]; 14 char buffer[1<<20|1],*S,*T; 15 #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,1<<20|1,stdin),S==T))?EOF:*S++) 16 inline void read(int &x){x=0; 17 register char c=getchar(); 18 while(c<'0'||c>'9')c=getchar(); 19 while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=getchar(); 20 } 21 int a[MAXN]; 22 int maxn,minn;int maxn_wei,minn_wei; 23 int n,m;int binn[MAXN]; 24 int f[21][MAXN];int f_min[21][MAXN];//区间极值的最小位置,最大位置 25 int wei[21][MAXN];int wei_min[21][MAXN]; 26 int ans_l[1000][1000]; 27 int ans_r[1000][1000]; 28 int tt,base;int Log[MAXN]; 29 void RMB(int l,int r)//通过权值查位置 30 { 31 int t=Log[r-l+1]; 32 maxn_wei=max(f[t][l],f[t][r+1-binn[t]]); 33 minn_wei=min(f_min[t][l],f_min[t][r+1-binn[t]]); 34 return ; 35 } 36 void RMB_wei(int l,int r)//通过位置察权值 37 { 38 int t=Log[r-l+1]; 39 maxn=max(wei[t][l],wei[t][r+1-binn[t]]); 40 minn=min(wei_min[t][l],wei_min[t][r+1-binn[t]]); 41 return ; 42 } 43 void work() 44 { 45 int t=Log[n]; 46 for(int j=1;j<=t;++j) 47 { 48 for(int i=1;i<=(n+1-binn[j]);++i) 49 { 50 f[j][i]=max(f[j-1][i],f[j-1][i+binn[j-1]]); 51 f_min[j][i]=min(f_min[j-1][i],f_min[j-1][i+binn[j-1]]); 52 wei[j][i]=max(wei[j-1][i],wei[j-1][i+binn[j-1]]); 53 wei_min[j][i]=min(wei_min[j-1][i],wei_min[j-1][i+binn[j-1]]); 54 } 55 } 56 for(int i=1;i<base;++i) 57 { 58 for(int j=i+1;j<=base;++j) 59 { 60 int l=kuan[i],r=kuan[j];//位置查权值 61 maxn=0;minn=0x7ffffffff;maxn_wei=r;minn_wei=l; 62 while(maxn-minn!=maxn_wei-minn_wei) 63 { 64 RMB_wei(minn_wei,maxn_wei); 65 RMB(minn,maxn); 66 } 67 ans_l[i][j]=minn_wei;ans_r[i][j]=maxn_wei; 68 // printf("ansl[%lld][%lld] i=%lld j=%lld ",minn_wei,maxn_wei,i,j); 69 } 70 } 71 } 72 73 signed main() 74 { 75 read(n); 76 tt=pow(n,0.66666); 77 Log[0]=-1;for(register int i=1;i<=n;++i) Log[i]=Log[i>>1]+1; 78 for(int i=1;i;++i) 79 { 80 if(i*tt>=n) 81 { 82 kuan[i]=n; 83 base=i; 84 break; 85 } 86 else 87 kuan[i]=i*tt; 88 } 89 for(int i=1;i<=n;++i) 90 { 91 read(a[i]); 92 f[0][a[i]]=i;f_min[0][a[i]]=i; 93 wei[0][i]=a[i];wei_min[0][i]=a[i]; 94 belong[i]=((i-1)/tt)+1; 95 } 96 binn[0]=1; 97 for(int i=1;i<=20;++i)binn[i]=(binn[i-1]<<1); 98 work(); 99 read(m); 100 for(int i=1;i<=m;++i) 101 { 102 int l,r; 103 read(l);read(r); 104 maxn=0;minn=0x7ffffffff; 105 maxn_wei=r;minn_wei=l; 106 RMB_wei(minn_wei,maxn_wei); 107 while(maxn-minn!=maxn_wei-minn_wei) 108 { 109 //printf("maxn=%lld minn=%lld maxn_wei=%lld minwei=%lld ",maxn,minn,maxn_wei,minn_wei); 110 RMB(minn,maxn); 111 int one=belong[minn_wei],two=belong[maxn_wei]; 112 //printf("one=%lld two=%lld ",one,two); 113 if(two>one+1&&one-1!=0) 114 { 115 if(ans_l[one][two-1]<=minn_wei&&ans_r[one][two-1]>=maxn_wei) 116 { 117 minn_wei=ans_l[one][two-1]; 118 maxn_wei=ans_r[one][two-1]; 119 //printf("min_wei=%lld ma_wei=%lld ",minn_wei,maxn_wei); 120 } 121 } 122 //printf("maxn=%lld minn=%lld maxn_wei=%lld minwei=%lld ",maxn,minn,maxn_wei,minn_wei); 123 RMB_wei(minn_wei,maxn_wei); 124 if(maxn-minn==maxn_wei-minn_wei)break; 125 } 126 printf("%lld %lld ",minn_wei,maxn_wei); 127 } 128 }