zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 64 (Rated for Div. 2) (线段树二分)

    题目:http://codeforces.com/contest/1156/problem/E

    题意:给你1-n  n个数,然后求有多少个区间[l,r] 满足    a[l]+a[r]=max([l,r])

    思路:首先我们去枚举区间肯定不现实,我们只能取把能用的区间去用,我们可以想下每个数当最大值的时候所做的贡献

    我们既然要保证这个数为区间里的最大值,我们就要从两边扩展,找到左右边界能扩展在哪里,这里你直接去枚举肯定不行

    这里我们使用了线段树二分去枚举左右区间最远能走到哪里,然后很暴力的去枚举短的那一边找出右边是否有满足条件的边界

    #include<bits/stdc++.h>
    #define maxn 200005
    #define mod 1000000007
    using namespace std;
    typedef long long ll;
    struct sss
    {
        int l,r;
        int val;
    }tree[maxn*4];
    int n;
    int a[maxn];
    int pos[maxn];
    void build(int cnt,int l,int r)
    {
        if(l==r){
            tree[cnt].l=l;
            tree[cnt].r=r;
            tree[cnt].val=a[l];
            return;
        }
        tree[cnt].l=l;
        tree[cnt].r=r;
        int mid=(l+r)/2; 
        build(cnt*2,l,mid);
        build(cnt*2+1,mid+1,r);
        tree[cnt].val=max(tree[cnt*2].val,tree[cnt*2+1].val); 
    } 
    int query(int cnt,int l,int r)
    {
        if(l<=tree[cnt].l&&r>=tree[cnt].r) return tree[cnt].val;
        int mid=(tree[cnt].l+tree[cnt].r)/2;
        if(r<=mid)  return query(cnt*2,l,r);
        else if(l>mid) return query(cnt*2+1,l,r);
        else{
            return max(query(cnt*2,l,mid),query(cnt*2+1,mid+1,r));
        } 
        
    }
    int dl(int x)
    {
        int val=a[x];
        int l=1;
        int r=x;
        while(r-l>1){
            int mid=(l+r)/2;
            int max_val=query(1,mid,x); //如果满足这个区间的最大值是这个数就继续扩张
            if(max_val==val)
            {
                r=mid;
            }
            else{
                l=mid;
            }
        }
        int max_val=query(1,l,x);
        if(max_val==val) return l;
        else return r; 
    }
    int dr(int x)
    {
        int val=a[x];
        int l=x;
        int r=n;
        while(r-l>1){
            int mid=(l+r)/2;
            int max_val=query(1,x,mid); 
            if(max_val==val)
            {
                l=mid;
            }
            else{
                r=mid;
            }
        }
        int max_val=query(1,x,r); 
        if(max_val==val) return r;
        else return l;
    }
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++)
        {
           scanf("%d",&a[i]); 
           pos[a[i]]=i;
        }
        build(1,1,n);
        int ans=0;
        for(int i=1;i<=n;i++){
            int l=dl(i);//找出左边界
            int r=dr(i);//找出右边界
            if(i-l<r-i){//枚举短的那一边
                for(int j=l;j<i;j++){
                    int other=a[i]-a[j];
                    if (other<=0||other>n)continue;
                    ans+=pos[other]>i&&pos[other]<=r;//确定令一边是否在这个区间里面
                }
            }
            else{
                for(int j=i+1;j<=r;j++){
                    int other=a[i]-a[j];
                    if (other<=0||other>n)continue;
                    ans+=pos[other]<i&&pos[other]>=l;
                }
            }
        } 
        printf("%d",ans);
    } 
  • 相关阅读:
    [USACO07DEC]观光奶牛Sightseeing Cows
    洛谷 U3348 A2-回文数
    LOJ #2037. 「SHOI2015」脑洞治疗仪
    1441 士兵的数字游戏
    BZOJ 1108: [POI2007]天然气管道Gaz
    P3047 [USACO12FEB]附近的牛Nearby Cows
    POJ 3061 Subsequence
    Hdu 5776 sum
    1052 最大M子段和
    1288 埃及分数
  • 原文地址:https://www.cnblogs.com/Lis-/p/10806663.html
Copyright © 2011-2022 走看看