題解 [51nod 1463] 找朋友

題解 [51nod 1463] 找朋友

題目描述

給定:

兩個長度爲n的數列A 、B

一個有m個元素的集合K

詢問Q次

每次詢問[l,r],輸出區間內滿足|Bi-Bj|∈K 的最大Ai+Aj

數據約定:

n,Q<=100000

m <= 10

0<=A[i]<=1000000000

1<=B[i]<=n

1<=K[i]<=n

保證B[i]互不相等

具體做法與心路歷程

這是線段樹的一道好題。類似題目有HH 的項鍊

想的時候就覺得做法可能跟HH的項鍊比較像,最後差一點就想出來了,還是看了題解。

這種題還是要多想一想。

具體做法

題目告訴了我們BB是一個排列,且m10m \leq 10,我們考慮對每個數來做。

枚舉ii,我們可以快速算出與BiB_i可以組成合法配對的另一個BjB_j,若我們對於每個ii都只考慮jj在其左邊的情況,那麼可以做到不重不漏。

把詢問離線下來,按rr排序。考慮在枚舉ii的時候統計所有r=ir=i的詢問的答案。

我們把Ai+AjA_i+A_j的值用線段樹存在jj的位置(jjii左邊),那麼詢問區間時相當於詢問l,rl,r的最大值。

這樣掃一遍即可。時間複雜度爲O(nmlogn+q)O(nmlogn+q)

Code\mathcal{Code}

/*******************************
Author:galaxy yr
LANG:C++
Created Time:2019年10月29日 星期二 19時56分59秒
*******************************/
#include<cstdio>
#include<algorithm>

using namespace std;

struct IO{
    template<typename T>
    IO & operator>>(T&res)
    {
        T q=1;char ch;
        while((ch=getchar())<'0' or ch>'9')if(ch=='-')q=-q;
        res=(ch^48);
        while((ch=getchar())>='0' and ch<='9') res=(res<<1)+(res<<3)+(ch^48);
        res*=q;
        return *this;
    }
}cin;

struct Query{
    int l,r,id;
    bool operator<(const Query & p) const
    {
        return r<p.r;
    }
};

const int maxn=1e5+10;
int a[maxn],b[maxn],n,m,q,s[11],ans[maxn],loc[maxn];
Query qry[maxn];

/*{{{線段樹*/

namespace SegmentTree{

    int tr[maxn*4];

    void update(int k)
    {
        tr[k]=max(tr[k<<1],tr[k<<1|1]);
    }

    void modify(int k,int l,int r,int pos,int val)
    {
        if(l==r)
        {
            tr[k]=max(tr[k],val);
            return;
        }
        int mid=(l+r)>>1;
        if(pos<=mid)
            modify(k<<1,l,mid,pos,val);
        else
            modify(k<<1|1,mid+1,r,pos,val);
        update(k);
    }

    int query(int k,int l,int r,int x,int y)
    {
        if(l>=x && r<=y) return tr[k];
        if(l>y  ||  r<x) return 0;
        int mid=(l+r)>>1;
        return max(query(k<<1,l,mid,x,y),query(k<<1|1,mid+1,r,x,y));
    }

};

/*}}}*/

void solve()
{
    int r=1;
    for(int i=1;i<=n;i++)
    {
        for(int k=1;k<=m;k++)
        {
            if(b[i]>s[k] && loc[b[i]-s[k]]<=i)
                SegmentTree::modify(1,1,n,loc[b[i]-s[k]],a[i]+a[loc[b[i]-s[k]]]);
            if(b[i]+s[k]<=n && loc[b[i]+s[k]]<=i)
                SegmentTree::modify(1,1,n,loc[b[i]+s[k]],a[i]+a[loc[b[i]+s[k]]]);
        }
        while(r<=q && qry[r].r<=i)
        {
            ans[qry[r].id]=SegmentTree::query(1,1,n,qry[r].l,qry[r].r);
            r++;
        }
    }
}

int main()
{
    //freopen("p1463.in","r",stdin);
    //freopen("p1463.out","w",stdout);
    cin>>n>>q>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) cin>>b[i],loc[b[i]]=i;
    for(int i=1;i<=m;i++) cin>>s[i];
    for(int i=1;i<=q;i++) cin>>qry[i].l>>qry[i].r,qry[i].id=i;
    sort(qry+1,qry+q+1);
    solve();
    for(int i=1;i<=q;i++)
        printf("%d\n",ans[i]);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章