题意:

给定一个数列,每次询问一个区间,问这个区间中的值可组成的周长最大的三角形的周长。

题解:

定理1:给定一些值,这些值中组成边长最大的三角形的三条边的大小排名一定是连续的。

证明:假如第k大,第k+1大,第k+2+b(b>0)大的三条边组成了一个边长最大的三角形,那么较小的两条边加起来长度大于第三边,又因为第k+2大的边比第k+2+b大的边长,因此把第k+2+b大的边换成第k+2大的边组成的三角形边长一定比原来大,矛盾。

定理2:如果三角形边长被限制为1e9以内的正整数,那么如果某组值存在周长最大的三角形,一定由前45大的边组成

证明:假如三角形由第44,45,46大的边组成,那么由定理1,前45大的边都组不成三角形,不妨令这个已组成的三角形的周长最小,三边分别为1,1,1,那么,如果要让第k,k+1,k+2大的三条边组不成三角形,必须令第k大的边大于等于后两条边之和。不难推出,第k大的边大于等于Febnacci[46-k],最大的边至少为Feb[45],已经超出1e9的范围,矛盾

有了这两个命题,此题的解法就一目了然,对于每个询问,找出该区间内前45大的值,依次询问排名连续的三个是否能构成三角形。

用主席树维护区间第k大,复杂度O(qlogn*c)    (c=45)

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int MAXN = 1e5 + ;
struct node {
int ls, rs, sum;
//左子树,右子树,该节点值
} ns[MAXN * ]; int ct;
//时间节点
int rt[MAXN * ];
//rt[i]代表a[i]在树上是第几个添加的 void cpy(int& now, int old) {
now = ++ct;
ns[now] = ns[old];
} void pushUp(int& now) {
ns[now].sum = ns[ns[now].ls].sum + ns[ns[now].rs].sum;
} void build(int& now, int l, int r) {
now = ++ct;
ns[now].sum = ;
if (l == r) return;
int m = (l + r) >> ;
build(ns[now].ls, l, m);
build(ns[now].rs, m + , r);
} void update(int& now, int old, int l, int r, int x) {
cpy(now, old);
//在旧树上添加新树
if (l == r) {
ns[now].sum++;
return;
}
int m = (l + r) >> ;
if (x <= m) update(ns[now].ls, ns[old].ls, l, m, x);
else update(ns[now].rs, ns[old].rs, m + , r, x);
pushUp(now);
//向上更新节点权值
} int query(int s, int t, int l, int r, int k) {
if (l == r) return l;
int m = (l + r) >> ;
int cnt = ns[ns[t].ls].sum - ns[ns[s].ls].sum;
//cout << s << " " << t << " " << cnt << endl;
if (k <= cnt) return query(ns[s].ls, ns[t].ls, l, m, k);
return query(ns[s].rs, ns[t].rs, m + , r, k - cnt);
//
} void init(int n) {
ct = ;
build(rt[], , n);
//从头开始建立主席树
} int a[MAXN], b[MAXN];
//b数组是a数组去重后的结果 int solve(int n,int m) { // int n, m;
// scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++) {
scanf("%d", &a[i]);
b[i] = a[i];
}
sort(b + , b + n + );
int sz = unique(b + , b + + n) - b - ;
init(sz);
//初始化树
for (int i = ; i <= n; i++) {
a[i] = lower_bound(b + , b + + sz, a[i]) - b;
//找出当前要添加的节点是b的第几个
update(rt[i], rt[i - ], , sz, a[i]);
//更新这个点
}
/*for (int i = 0; i <= 5 * n; i++) {
printf("%d, rt = %d, ls = %d, rs = %d, sum = %d\n", i, rt[i], ns[rt[i]].ls, ns[rt[i]].rs, ns[rt[i]].sum);
}*/
while (m--) {
int ll,rr;
scanf("%d %d",&ll,&rr);
vector<int> vec;
vec.clear();
for(int i=;i<=min(,rr-ll+);i++){
vec.push_back(b[query(rt[ll-],rt[rr],,sz,rr-ll+-i)]);
// printf("push%d\n",vec[vec.size()-1]);
}
LL ans=-;
for(int i=;i<vec.size();i++){
if(vec[i-]<vec[i-]+vec[i]){
ans=1LL*vec[i-]+vec[i]+vec[i-];
break;
}
}
printf("%lld\n",ans);
// printf("%d\n", b[query(rt[s - 1], rt[t], 1, sz, k)]);
}
return ;
}
int main(){
int n,m;
while(){
int rep=scanf("%d %d",&n,&m);
if(rep==-)break;
else {
// memset()
solve(n,m);
}
}
}
05-28 10:55