妄想集合

题目

链接:https://ac.nowcoder.com/acm/contest/11180/D
来源:牛客网

开始有 nnn 个可重集合,开始时每一个集合中都有一个数,有 m 个操作。

  • Quant l r x:往编号在 l∼r 的每个集合中加入一个数 x。
  • Ask l r:询问能否从 l∼r 的集合中取出三个数使得他们能作为边长组成一个三角形(即最小两个和要大于最大的)。

输入描述:

第一行两个整数 n,m (1≤n,m≤105)。
接下来一行 n 个数表示每个集合中初始的一个数 ai 。
接下来 m 行每行表示一个操作。
保证操作加入的数字和最开始的数字均为正整数且不超过 10^9 且询问区间合法 (1≤l≤r≤n) 。

输出描述:

对于每个 Ask 操作,输出一行表示答案,能则输出 YES ,否则输出 NO。



题解
关于三角形与斐波那契数列的关系
结论:当数列中的所有数都是斐波那契数列中的数的时候,任意三个数不能组成三角形.(证明很简单我这里就略过了)

算法1:

因为题目给出了一个条件:保证操作加入的数字和最开始的数字均为正整数且不超过 $10^9$所以我首先打了个表发现当i==45的时候数列的值超过了$10^9$,所以由鸽笼原理可以知道如果我们集合中的数字超过了45个,那样一定可以组成三角形 所以在这里对于Ask我们先求一下[l,r]的集合的数目,如果数目大于45则一定可以,小于3一定不行,如果数目在此之间的话我们只需要把集合中的数字取出来排序之后暴力枚举三个值能不能构成三角形 在这里看上去时间复杂度很高,但是我们仔细想一想,因为保证了集合中的数字至少有一个所以我们枚举的集合数一定是小于等于45个的那样的.

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+100;
vector<int>v[maxn];
struct node{
    int l,r,sum;
}t[maxn];
int n,m,x;
char s[maxn];
void push(int p){
    t[p].sum=(t[2*p].sum+t[2*p+1].sum);
}
void build(int p,int l,int r){
    t[p].l=l;
    t[p].r=r;
    if(l==r){
        t[p].sum=1;
        return ;
    }
    int mid=(t[p].l+t[p].r)/2;
    build(2*p,l,mid);
    build(2*p+1,mid+1,r);
    push(p);
}
void update(int p,int l,int r,int x){
    if(t[p].sum/(t[p].r-t[p].l+1)>=46) return ;
    if(t[p].l==t[p].r){
        t[p].sum++;
        v[t[p].l].push_back(x);
        return ;
    }
    int mid=(t[p].l+t[p].r)/2;
    if(l<=mid){
        update(2*p,l,r,x);
    }
    if(r>mid){
        update(2*p+1,l,r,x);
    }
    push(p);
}
int query(int p,int l,int r){
    if(t[p].l>=l&&t[p].r<=r){
        return t[p].sum;
    }
    int ans=0;
    int mid=(t[p].l+t[p].r)/2;
    if(l<=mid){
        ans+=query(2*p,l,r);
    }
    if(r>mid){
        ans+=query(2*p+1,l,r);
    }
    return ans;
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>x;
        v[i].push_back(x);
    }
    build(1,1,n);
    int l,r,x;
    while(m--){
        scanf("%s%d%d",s,&l,&r);
        if(s[0]=='A'){
            int sum=query(1,l,r);
            if(sum>46){
                cout<<"YES"<<"\n";
            }
            else if(sum<=2){
                cout<<"NO"<<"\n";
            }
            else{
                vector<int>tmp;
                for(int i=l;i<=r;i++){
                    for(auto x:v[i]){
                        tmp.push_back(x);
                    }
                }
                sort(tmp.begin(),tmp.end());
                int flag=0;
                for(int i=0;i+2<tmp.size();i++){
                    if(tmp[i]+tmp[i+1]>tmp[i+2]){
                        flag=1;
                        break;
                    }
                }
                if(flag){
                    cout<<"YES"<<"\n";
                }
                else{
                    cout<<"NO"<<"\n";
                }
            }
        }
        else {
            scanf("%d",&x);
            update(1,l,r,x);
        }
    }
}

 

  

 



posted @ 2021-11-10 23:11  lipu123  阅读(56)  评论(0)    收藏  举报