- 题意:
- 给出n个木棒,每次询问区间[l,r],问你选择任意三根木棒能够构成的最大的三角形,如果不存在三角形,输出-1
- 题解:
- 肯定都知道三角形的三边的定理,任意俩边之和大于第三边,
- 假设从最小的三角形都不匹配,
- 1,2,3,5,8,13,,,,
- 形成了斐波那契数列,第44项超过1e9,那么只需枚举前44项三角形就行了,如果还是没有符合的输出-1
- 找第k大值可以用主席树区间查找
- 代码:
#include <bits/stdc++.h> using namespace std; #define ll long long const int maxx = 2e5+7; int n,m,q,cnt,a[maxx],b[maxx],x,y,k; int t[maxx*50],ls[maxx*50],rs[maxx*50],sum[maxx*50]; int build(int l,int r) { int now = ++cnt; if(l < r) { int mid = (l+r)>>1; ls[now]=build(l,mid); rs[now]=build(mid+1,r); } return now; } void build_new(int mark,int loc) { t[mark] = ++cnt; sum[cnt] = sum[t[mark-1]] +1; int l=1,r=m,now=cnt,still=t[mark-1]; for(;ls[still] || rs[still];) { int mid = (l+r)>>1; if(loc > mid) { ls[now] = ls[still]; rs[now] =++cnt; sum[rs[now]] = sum[rs[still]]+1; now = rs[now]; still = rs[still]; l = mid+1; } else { rs[now] = rs[still]; ls[now] = ++cnt; sum[ls[now]] = sum[ls[still]] +1; now = ls[now]; still = ls[still]; r = mid; } } } int query(int a,int b,int l,int r,int k) { if(l == r) return l; int lm = sum[ls[b]] - sum[ls[a]]; int mid = (l+r)>>1; if(k<=lm) return query(ls[a],ls[b],l,mid,k); return query(rs[a],rs[b],mid+1,r,k-lm); } int main() { while(~scanf("%d%d",&n,&q)) { for(int i=1;i<=n;i++) { scanf("%d",&a[i]); b[i] = a[i]; } sort(b+1,b+1+n); m = unique(b+1,b+1+n)-b-1; t[0] = build(1,m); for(int i=1;i<=n;i++) { int loc = lower_bound(b+1,b+1+m,a[i]) - b; build_new(i,loc); } for(int i=1;i<=q;i++) { scanf("%d %d",&x,&y); int len = y-x+1; int flag = 45; int k1 = 0,k2 = 0,k3 = 0; ll ans = -1; while(len >= 3 && flag>=0) { if(k1 && k2 && k3){ k1 = k2,k2 = k3; k3 = b[query(t[x-1],t[y],1,m,len-2)]; } else{ k1 = b[query(t[x-1],t[y],1,m,len)]; k2 = b[query(t[x-1],t[y],1,m,len-1)]; k3 = b[query(t[x-1],t[y],1,m,len-2)]; } if((k1<k2+k3)&&(k2<k1+k3)&&(k3<k1+k2)) { ans = 1LL*k1 + 1LL*k2 + 1LL*k3; break; } len--; flag--; } printf("%lld\n",ans); } } return 0; }