GPLT上理选拔-K-鸽巢定理+线段树

2023大厂真题提交网址(含题解):

www.CodeFun2000.com(http://101.43.147.120/)

最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。
在这里插入图片描述

题目大意:

https://ac.nowcoder.com/acm/contest/13276/K

very clear

题目思路:

1.化解问题:
给你 n n n个数 a i ≤ 1 e 5 a_i \leq 1e5 ai1e5.是否能够从里面选出三个数使得构成三角形.

2.结论:
n > 25 n > 25 n>25时,答案一定存在。

要选出三角形,一定是相邻的三个数可能性最大。那么要求一个都不存在。那么就是对于任意一项要满足 a [ i ] > a [ i − 1 ] + a [ i − 2 ] a[i] > a[i-1]+a[i-2] a[i]>a[i1]+a[i2].那么这样的数列的递增至少是斐波那契数列。所以当 n > 25 n > 25 n>25时,根据鸽巢原理答案一定存在。

3.有了这个结论。我们就可以直接暴力做了。线段树每个节点维护两个vector.暴力合并。当 s z > 25 sz>25 sz>25。则只加 s z sz sz.无需再暴力合并vector.

然后查询就分情况即可。具体细节看代码。

#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
#define ll long long
#define tl (t<<1)
#define tr (t<<1|1)
#define mid ((r + l) >> 1)
const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
const ll inf = 1e18;
const int mx = 25;
int lazy[maxn<<2] , c[maxn] , b[maxn];
vi a[maxn<<2][2];
int sz[maxn<<2][2];
void pushup(int t)
{
    for (int i = 0 ; i <= 1 ; i++){
        if (sz[tl][i] + sz[tr][i] <= mx){
            a[t][i] = a[tl][i];
            for (auto g : a[tr][i]) a[t][i].pb(g);
        }
        sz[t][i] = sz[tl][i] + sz[tr][i];
    }
}
void D(int t)
{
    swap(sz[t][0] , sz[t][1]);
    swap(a[t][0] , a[t][1]);
    lazy[t] ^= 1;
}
void pushdown(int l,int r,int t)
{
    if(lazy[t])
    {
        D(tl);
        D(tr);
        lazy[t] = 0;
    }
}
void Build(int l,int r,int t)
{
    lazy[t] = 0;
    if(l == r)
    {
        int g = b[l];
        sz[t][g] = 1;
        sz[t][!g] = 0;
        a[t][g].pb(c[l]);
        return ;
    }
    Build(l , mid , tl);
    Build(mid + 1 , r , tr);
    pushup(t);
}
void Update(int L,int R,int l,int r,int t)
{
    if(L <= l && r <= R){
        D(t);
        return ;
    }
    pushdown(l,r,t);
    if(L <= mid)
        Update(L,R,l,mid,tl);
    if(R > mid)
        Update(L,R,mid+1,r,tr);
    pushup(t);
}
struct Node
{
    int sz;
    vi a;
    void mer (Node f)
    {
        if (sz + f.sz <= mx)
            for (auto g : f.a) a.pb(g);
        sz += f.sz;
    }
};
Node Query(int L,int R,int l,int r,int t)
{
    if(L <= l && r <= R){
        Node res;
        res.a = a[t][1];
        res.sz = sz[t][1];
        return res;
    }
    pushdown(l,r,t);
    Node ans = {0 , vi()};
    if(L <= mid){
        Node res = Query(L,R,l,mid,tl);
        ans.mer(res);
    }
    if(R > mid){
        Node res = Query(L,R,mid+1,r,tr);
        ans.mer(res);
    }
    return ans;
}

int main()
{
    ios::sync_with_stdio(false);
    int n , m ; cin >> n >> m;
    for (int i = 1 ; i <= n ; i++){
        cin >> c[i];
    }
    for (int i = 1 ; i <= n ; i++){
        cin >> b[i];
    }
    Build(1 , n , 1);
    for (int i = 1 ; i <= m ; i++){
        int op , l , r; cin >> op >> l >> r;
        if (op == 1){
            Update(l , r , 1 , n , 1);
        }else {
            Node res = Query(l , r , 1 , n , 1);
            if (res.sz > mx) cout << "YES" << endl;
            else {
                sort(res.a.begin() , res.a.end());
                int n = res.a.size();
                bool ok = false;
                for (int i = 2 ; i < n ; i++){
                    if (res.a[i - 2] + res.a[i - 1] > res.a[i]) ok = true;
                }
                if (ok) cout << "YES" << endl;
                else cout << "NO" << endl;
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值