1. 程式人生 > >線段樹模板題(結構體&一維陣列)(區間最值,求和)

線段樹模板題(結構體&一維陣列)(區間最值,求和)

1099: [視訊]線段樹(元問題byscy)線性結構求極值和修改
時間限制: 1 Sec 記憶體限制: 128 MB
提交: 496 解決: 165
[提交][狀態][討論版]
題目描述

【題意】
給出N個數,兩種操作:
1、C x y:修改第x個數的值為y;
2、P x y:求第x到第y個的最大值,注:x未必比y小
【輸入格式】
第一行輸入N和M(0 < N< = 200000,0 < M < 5000),N表示有N個數,M表示有M個操作
下來N個數
然後是M個操作。
【輸出格式】
遇到P操作的時候,輸出結果。
【樣例輸入】
5 6
1 2 3 4 5
P 1 5
C 3 6
P 3 4
P 4 5
C 2 9
P 1 5
【樣例輸出】
5
6
5
9

#include<iostream>
#include<cstring>
using namespace std;
int a[210000];//員工一開始只負責表達自己的值

struct node{
int l,r,lc,rc,c;}tr[410000];

int len ;
void bt(int l,int r)//申請一個管理者,管理第l到第r個員工
{

    len++;
    int now=len;//now記錄當前管理者的編號
    tr[now].l=l;
    tr[now].r=r;
    tr[now].lc=tr[now].rc=-1;//一開始當前now管理者的左右副總都沒有人,為-1
if (l==r) tr[now].c=a[l];l==r;//表示當前管理者只有一個人 else//如果管理的人大於1,就有權申請兩個副總經理幫忙管理人。 { int mid=(l+r)/2; tr[now].lc=len+1;bt(l,mid); tr[now].rc=len+1;bt(mid+1,r); tr[now].c=max(tr[tr[now].lc].c,tr[tr[now].rc].c);//詢問左右副總的管理範圍的特徵值 } } void change(int now ,int x,int k )//在當前now管理者,所管理的範圍內,把管理第x
個員工的管理者的值改為k { if (tr[now].l==tr[now].r) {tr[now].c=k;return ;} int lc=tr[now].lc,rc=tr[now].rc; int mid=(tr[now].l+tr[now].r)/2; if (x<=mid) change(lc,x,k); else if (mid+1<=x) change(rc,x,k); tr[now].c=max(tr[lc].c,tr[rc].c); } int findmax(int now,int l,int r) { if (l==tr[now].l&&tr[now].r==r) return tr[now].c; int lc=tr[now].lc,rc=tr[now].rc; int mid=(tr[now].l+tr[now].r)/2; if (r<=mid) return findmax(lc,l,r); else if (mid+1<=l) return findmax(rc,l,r); else return max(findmax(lc,l,mid),findmax(rc,mid+1,r)); } int main() { int n,m,x,y; char s; cin>>n>>m; for (int i=1;i<=n;i++) { cin>>a[i]; } len=0;//一開始,有0個管理者 bt(1,n); for (int i=0;i<m;i++) { cin>>s>>x>>y; if (s=='C') { change(1,x,y); } else { if (x>y) cout<<findmax(1,y,x)<<endl; else cout<<findmax(1,x,y)<<endl; } } return 0; }

再給出一個使用一維陣列的演算法

#include <iostream>
using namespace std;
int maxnum[400005];
int a[200005];
void bt(int now ,int l,int r)
{
    if (l==r) maxnum[now]=a[l];
    else
    {
        int mid=(l+r)/2;
        bt(now*2,l,mid);
        bt(now*2+1,mid+1,r);
        maxnum[now]=max(maxnum[now*2],maxnum[now*2+1]);
    }
}
void change(int now,int l,int r,int x,int k)//更新a[x]=k;
{
    int mid=(l+r)/2;
    if (l==r) maxnum[now]=k;
    else
    {
        if (x<=mid)
            change(now*2,l,mid,x,k);
        else
            change(now*2+1,mid+1,r,x,k);
        maxnum[now]=max(maxnum[2*now],maxnum[2*now+1]);
    }
}
int findmax(int now ,int l,int r,int x,int y)
{
    int mid=(l+r)/2;
    int ans=-1;

    if (x<=l&&r<=y) return maxnum[now];//當前節點完全包含在查詢區間內
    if (x<=mid) ans=max(ans,findmax(now*2,l,mid,x,y));
    if (mid<y) ans=max(ans,findmax(now*2+1,mid+1,r,x,y));
    return ans;
}
int main()
{
    int n,m;
    char s;int x,y;
    cin>>n>>m;
    for (int i=1;i<=n;i++)
        cin>>a[i];
    bt(1,1,n);
    for(int i=0;i<m;i++)
    {
        cin>>s>>x>>y;
        if (s=='C')
            change(1,1,n,x,y);
        else
        {
           if (x<y) cout<<findmax(1,1,n,x,y)<<endl;
           else cout<<findmax(1,1,n,y,x)<<endl;
        }
    }

    return 0;
}

加上了求區間最小值,和求和的內容

#include<iostream>
using namespace std;
int num[20000];
int maxnum[40000];
int minnum[40000];
int sumnum[40000];
void bt(int now ,int l,int r)
{
    if (l==r)
    {
        maxnum[now]=num[l];
        minnum[now]=num[l];
        sumnum[now]=num[l];
    }
    else
    {
        int mid=(l+r)/2;
        bt(now*2,l,mid);
        bt(now*2+1,mid+1,r);
        maxnum[now]=max(maxnum[now*2],maxnum[now*2+1]);
        minnum[now]=min(minnum[now*2],maxnum[now*2+1]);
        sumnum[now]=sumnum[now*2]+sumnum[now*2+1];
    }
}
void change(int now,int l,int r,int x,int k)//將a[x]更新為k
{
    if (l==r)
    {
        maxnum[now]=k;
        minnum[now]=k;
        sumnum[now]=k;
    }
    else
    {
        int mid=(l+r)/2;
        if (x<=mid) change(now*2,l,mid,x,k);
        else change(now*2+1,mid+1,r,x,k);

        maxnum[now]=max(maxnum[now*2],maxnum[now*2+1]);
        minnum[now]=min(minnum[now*2],maxnum[now*2+1]);
        sumnum[now]=sumnum[now*2]+sumnum[now*2+1];
    }
}
int findmax(int now,int l,int r,int x,int y)
{

    if (x<=l&&r<=y)
        return maxnum[now];
    else
    {
        int maxl=-1,maxr=-1;
        int mid=(l+r)/2;
        if(x<=mid)
           maxl= findmax(now*2,l,mid,x,y);
        if (mid<y)
            maxr=findmax(now*2+1,mid+1,r,x,y);
        return max(maxl,maxr);
    }
}
int findmin(int now,int l,int r,int x,int y)
{
    if (x<=l&&r<=y)
        return minnum[now];
    else
    {
        int mid=(l+r)/2;
        int minl=1<<29,minr=1<<29;
        if (x<=mid) minl=findmin(now*2,l,mid,x,y);
        if (mid<y) minr=findmin(now*2+1,mid+1,r,x,y);
        return min(minl,minr);
    }
}
int findsum(int now,int l,int r,int x,int y)
{

    if (x<=l&&r<=y) return sumnum[now];
    else
    {

        int mid=(l+r)/2;
        int suml=0,sumr=0;
        if (x<=mid) suml=findsum(now*2,l,mid,x,y);
        if (mid<y)  sumr=findsum(now*2+1,mid+1,r,x,y);
        return suml+sumr;
    }
}
int main()
{
    int n,m;
    char s;
    int x;
    int y;
    cin>>n>>m;
    for (int i=1;i<=n;i++)
    {
        cin>>num[i];
    }
    bt(1,1,n);
    for(int i=0;i<m;i++)
    {

        cin>>s>>x>>y;
        if (s=='C')
        {
            change(1,1,n,x,y);
        }
        else
        {
            cout<<findmax(1,1,n,x,y)<<endl;
            cout<<findmin(1,1,n,x,y)<<endl;
            cout<<findsum(1,1,n,x,y)<<endl;
        }
    }
    return 0;
}