列表

详情


NC211736. 曲调

描述

牛牛喜欢拉小提琴,优雅的曲调对牛牛在听觉上是一种极大程度的享受。 
牛牛不是普通人,也不是正常人,他有一种奇怪的办法衡量一段曲子的不和谐程度。
一首曲子由n个音符构成,每个音符结合其持续时长和声调高低对应其一个整数,一段曲子的不和谐程度为这段曲子所对应整数序列中,和的绝对值 最小的 子段的和的绝对值。
现在牛牛听到了一首曲子,为了考验你,他会给你这个曲子,并询问你m个区间的不和谐程度。
聪明的你能回答他的问题么?
(注:子段不为空)

输入描述

第一行 两个正整数n,m
第二行 n 个数,表示这首曲子
接下来m行每行两个数l,r表示询问的区间

输出描述

m行每行一个数表示对应询问的答案

示例1

输入:

5 2
4 -1 2 -1 3
1 5
3 5

输出:

0
1

说明:

询问1对应为 [2,4],|-1+2-1|=0

询问2对应为 [4,4], |-1|=1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 688ms, 内存消耗: 63080K, 提交时间: 2020-10-01 21:30:08

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+5;
const ll INF=0x3f3f3f3f3f3f3f3f;
struct node{
    int l,r,id;
    bool operator<(const node &a)const{
        return r==a.r?l<a.l:r<a.r;
    }
}q[N];
int n,m;
ll mx[N<<2],ans[N],a[N],mi;
vector<ll>V[N<<2];
void build(int l,int r,int rt){
    mx[rt]=INF;
    for(int i=l;i<=r;i++)V[rt].push_back(a[i]);sort(V[rt].begin(),V[rt].end());
    if(l==r)return ;
    int mid=l+r>>1;
    build(l,mid,rt<<1);build(mid+1,r,rt<<1|1);
}
void update(int l,int r,int R,int x,int rt){
    if(r<=R){
        auto it=upper_bound(V[rt].begin(),V[rt].end(),a[x]);
        if(it!=V[rt].end())mx[rt]=min(mx[rt],*it-a[x]);
        if(it!=V[rt].begin())mx[rt]=min(mx[rt],a[x]-*(--it));
        if(mx[rt]>=mi)return ;
        if(l==r){mi=min(mi,mx[rt]);return ;}
    }
    int mid=l+r>>1;
    if(R>mid)update(mid+1,r,R,x,rt<<1|1);
    update(l,mid,R,x,rt<<1);
    mx[rt]=min(mx[rt<<1],mx[rt<<1|1]);
    mi=min(mi,mx[rt]);
}
ll query(int l,int r,int L,int R,int rt){
    if(L<=l&&r<=R)return mx[rt];
    int mid=l+r>>1;ll ans=INF;
    if(L<=mid)ans=min(ans,query(l,mid,L,R,rt<<1));
    if(mid<R)ans=min(ans,query(mid+1,r,L,R,rt<<1|1));
    return ans;
}
int main(){
    scanf("%d %d",&n,&m);n++;
    for(int i=2;i<=n;i++)scanf("%lld",&a[i]),a[i]+=a[i-1];
    build(1,n,1);
    for(int i=1;i<=m;i++)scanf("%d %d",&q[i].l,&q[i].r),q[i].id=i;sort(q+1,q+m+1);
    int now=1;
    for(int i=2;i<=n;i++){
        mi=INF;
        update(1,n,i-1,i,1);
        for(;now<=m&&q[now].r+1==i;now++)
            ans[q[now].id]=query(1,n,q[now].l,i-1,1);
    }
    for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
	return 0;
}

C++(clang++11) 解法, 执行用时: 818ms, 内存消耗: 41072K, 提交时间: 2021-02-07 21:20:18

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3fll
using namespace std;
const int N=3e5+5;
typedef long long ll;
vector<ll>t[400005];
ll a[N],mn,sum[400005],ans[N];
int n,m;
struct node
{
    int l,r,id;
    bool operator<(const node&o)const
    {
        return r<o.r;
    }
}q[N];
void build(int l,int r,int k)
{
    for(int i=l;i<=r;i++) t[k].push_back(a[i]);
    sort(t[k].begin(),t[k].end());
    if(l==r) return;
    int m=l+r>>1;
    build(l,m,k<<1);build(m+1,r,k<<1|1);
}
void Insert(int l,int r,int k,int x,ll v)
{
    if(r<x)
    {
        vector<ll>::iterator it=lower_bound(t[k].begin(),t[k].end(),v);
        if(it!=t[k].end()) sum[k]=min(sum[k],abs(v-(*it)));
        if(it!=t[k].begin()) it--,sum[k]=min(sum[k],abs(v-(*it)));
        if(sum[k]>=mn) return;
    }
    if(l==r) {mn=min(mn,sum[k]);return;}
    int m=l+r>>1;
    if(x>m) Insert(m+1,r,k<<1|1,x,v);
    Insert(l,m,k<<1,x,v);
    sum[k]=min(sum[k],min(sum[k<<1],sum[k<<1|1]));
    mn=min(mn,sum[k]);
}
ll query(int l,int r,int k,int x)
{
    if(r<x) return inf;
    if(l>=x) return sum[k];
    int m=l+r>>1;
    return min(query(l,m,k<<1,x),query(m+1,r,k<<1|1,x));
}
int main()
{
    memset(sum,inf,sizeof(sum));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]+=a[i-1];
    for(int i=1;i<=m;i++)
        scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
    sort(q+1,q+1+m);
    build(0,n,1);
    for(int i=0,j=1;i<=n;i++)
    {
        mn=inf;
        Insert(0,n,1,i,a[i]);
        while(j<=m&&q[j].r==i)
            ans[q[j].id]=query(0,n,1,q[j].l-1),j++;
    }
    for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
}

上一题