寒假刷題22:"Ray, Pass me the dishes!" (UVALive - 3938 )

題目鏈接:

https://vjudge.net/problem/UVALive-3938

題目解析:

構造線段樹,維護最大區間和,最大前綴和,最大後綴和,通過分治的思想進行區間合併。

AC代碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
 
const int maxn=500000+10;
typedef long long ll;
typedef pair<int,int> par;
ll a[maxn];
int n,q,temp,l,r;
ll sum[maxn];//前綴和,要求一段區間的值就是sum[r]-sum[l-1]
 
struct node
{
    int l,r,prer,sufl;//左右節點,最大前綴和終點,最大後綴和起點
    par sub;//結果
}nodes[maxn<<2];
ll cal(par x)
{
    return sum[x.second]-sum[x.first-1];//求區間和
}
//比較兩個區間和大小
par cmp(par x,par y)
{
    ll a=cal(x);
    ll b=cal(y);
    if(a!=b) return a>b?x:y;
    return x<y?x:y;
}
//合併
node com(node x,node y)
{
    node res;
    res.l=x.l;
    res.r=y.r;
    res.prer=cmp(par(x.l,x.prer),par(x.l,y.prer)).second;//新節點的最大前綴和終點,畫個圖就能理解
    res.sufl=cmp(par(y.sufl,y.r),par(x.sufl,y.r)).first;//新節點的最大後綴和
    //答案的區間只會有三種情況,要麼左邊,要麼右邊,要麼中間。
    res.sub=cmp(par(x.sufl,y.prer),cmp(x.sub,y.sub));
    return res;
}
void build(int l,int r,int root)
{
    if(l==r)
    {
        //根節點
        nodes[root].l=nodes[root].r=nodes[root].prer=nodes[root].sufl=l;
        nodes[root].sub=par(l,l);
        return;
    }
    int m=(l+r)/2;
    build(l,m,root*2);//左節點
    build(m+1,r,root*2+1);//右節點
    nodes[root]=com(nodes[root*2],nodes[root*2+1]);//合併
}
node query(int l,int r,int root)
{
    if(nodes[root].l>=l&&nodes[root].r<=r)return nodes[root];
    int m=(nodes[root].l+nodes[root].r)/2;
    node res;
    if(l<=m&&r>m)res=com(query(l,r,root*2),query(l,r,root*2+1));//查詢區間包含左右合集
    else if (l<=m)  res=query(l,r,root*2); //l<=m且r<=m,說明只在左邊
    else res=query(l,r,root*2+1);   //l>m且r>m說明只在右邊
    return res;
}
int main()
{
    int index=1;
    while(scanf("%d%d",&n,&q)!=EOF)
    {
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            sum[i]=a[i]+sum[i-1];
        }
        build(1,n,1);//構建線段樹
        printf("Case %d:\n",index++);
        for(int i=1;i<=q;++i)
        {
            scanf("%d%d",&l,&r);
            par ans=query(l,r,1).sub;
            printf("%d %d\n",ans.first,ans.second);
        }
    }
    return 0;
}

 

發佈了56 篇原創文章 · 獲贊 22 · 訪問量 6300
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章