侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130562 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

Educational Codeforces Round 64 (Rated for Div. 2) (线段树二分)

2023-04-06 星期四 / 0 评论 / 0 点赞 / 78 阅读 / 5639 字

题目:http://codeforces.com/contest/1156/problem/E 题意:给你1-n n个数,然后求有多少个区间[l,r] 满足 a[l]+a[r]=max([l,

... .

题目: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 1000000007using 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 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,r);    else if(l>mid) return query(cnt*2+1,r);    else{        return max(query(cnt*2,mid),query(cnt*2+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,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,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);} 
. . .. ...

广告 广告

评论区