ACM新手DAY 17 線段樹

題解

A - 敵兵佈陣 (樣題)

  • 單點更新+區間求和查詢
  • 線段樹
#include<bits/stdc++.h>
using namespace std;
int sum[50010*4];
void buildtree(int l,int r,int k)//k是當前節點的編號
{
    if(l==r) {cin>>sum[k]; return;}
    int mid=(l+r)/2;//以下是後序遍歷部分
    buildtree(l,mid,2*k);
    buildtree(mid+1,r,2*k+1);
    sum[k]=sum[2*k]+sum[2*k+1];
}
///單點更新
void update(int l,int r,int k,int val,int pos)//這裏的l,r,k和上面函數裏面的含義一樣
{
    if(l==r) {sum[k]+=val; return;}
    int mid=(l+r)/2;
    ///下面的if...else部分是找pos節點的
    if(pos<=mid) update(l,mid,2*k,val,pos);
    else update(mid+1,r,2*k+1,val,pos);
    sum[k]=sum[2*k]+sum[2*k+1];
}
///區間查詢部分
int query(int l,int r,int ql,int qr,int k)
{
    int mid=(l+r)/2;
    if(l==ql&&r==qr) return sum[k];
    if(ql>mid) return query(mid+1,r,ql,qr,2*k+1);
    else if(qr<=mid) return query(l,mid,ql,qr,2*k);
    else return query(l,mid,ql,mid,2*k)+query(mid+1,r,mid+1,qr,2*k+1);
}
int main()
{
    ios::sync_with_stdio(0),cin.tie(0);
    int T;
    cin>>T;
    int CS=1;
    string q;
    while(T--)
    {
        int n;
        cin>>n;
        buildtree(1,n,1);
        cout<<"Case "<<CS++<<":"<<endl;
        while(cin>>q)
        {
            if(q[0]=='E') break;
            int a,b;
            cin>>a>>b;
            if(q[0]=='A')
            {
                update(1,n,1,b,a);
            }
            else if(q[0]=='S')
            {
                update(1,n,1,-b,a);
            }
            else if(q[0]=='Q')
            {
                cout<<query(1,n,a,b,1)<<endl;
            }
        }
    }
}

B - I Hate It

  • 區間最大值查詢
  • 線段樹
  • 線段樹的基本應用,把求和處理成最大值。
#include<iostream>
#include<cmath>
using namespace std;
const int mx = 200000;
int Maxn[mx*4];
void buildtree(int l,int r,int k)//k是當前節點的編號
{
    if(l==r) {cin>>Maxn[k]; return;}
    int mid=(l+r)/2;//以下是後序遍歷部分
    buildtree(l,mid,2*k);
    buildtree(mid+1,r,2*k+1);
    Maxn[k]=max(Maxn[2*k],Maxn[2*k+1]);
}
///單點更新
void update(int l,int r,int k,int val,int pos)//這裏的l,r,k和上面函數裏面的含義一樣
{
    if(l==r) {Maxn[k] = val; return;}
    int mid=(l+r)/2;
    ///下面的if...else部分是找pos節點的
    if(pos<=mid) update(l,mid,2*k,val,pos);
    else update(mid+1,r,2*k+1,val,pos);
    Maxn[k]=max(Maxn[2*k],Maxn[2*k+1]);
}
///區間查詢部分
int query(int l,int r,int ql,int qr,int k)
{
    int mid=(l+r)/2;
    if(l==ql&&r==qr) return Maxn[k];
    if(ql>mid) return query(mid+1,r,ql,qr,2*k+1);
    else if(qr<=mid) return query(l,mid,ql,qr,2*k);
    else return max(query(l,mid,ql,mid,2*k), query(mid+1,r,mid+1,qr,2*k+1));
}
int main()
{
    ios::sync_with_stdio(0),cin.tie(0);
    int n, m;
    string q;
    while(cin>>n>>m)
    {
        buildtree(1,n,1);
        while(m--)//m次查詢
        {
            cin >> q;
            int a,b;
            cin >> a >> b;
            if(q[0]=='U')
            {
                update(1,n,1,b,a);
            }
            else if(q[0]=='Q')
            {
                cout<<query(1,n,a,b,1)<<endl;
            }
        }
    }
    return 0;
}

D - Billboard

題目:有個高h,寬w的公告板,要貼n張公告,每個公告的長度是k,高度固定爲1,公告放的要儘可能靠上並儘可能靠左,每給出一張公告,要求這個公告在滿足要求的情況下放在了第幾層。

按照線段樹的做法的話,因爲公告的高度固定爲1,可以對公告板的高度進行線段花費,將其現在的寬度值存起來,然後每次遍歷從左子樹開始往下走,知道走到葉子節點滿足要求即可。
將原來的模板結合結構體攜帶信息。

#include <stdio.h>
#include <iostream>
using namespace std;
int h,w,n;
int ans;
struct node
{
    int l,r,n;
} a[1000000];
void buildtree(int l,int r,int i,int w)//建樹
{
    a[i].l=l;
    a[i].r=r;
    a[i].n=w;
    if(l!=r)
    {
        int mid=(l+r)/2;
        buildtree(l,mid,2*i,w);
        buildtree(mid+1,r,2*i+1,w);
    }
}
void update(int i,int x)
{
    if(a[i].l == a[i].r)//到了葉子節點,葉子節點的值既是層數
    {
        a[i].n-=x;//該層寬度減少
        ans = a[i].l;
        return ;
    }
    if(x<=a[2*i].n)//符合要求搜左子樹
        update(2*i,x);
    else//否則右子樹
        update(2*i+1,x);
    a[i].n = max(a[2*i].n,a[2*i+1].n);//將左右子樹裏能放的最大長度存入父親節點,進行更新
}
int main()
{
    int k;
    while(~scanf("%d%d%d",&h,&w,&n))
    {
        h = min(h, n);//min!!!!佔得高度最大爲n,這樣就減少了一些情況
        buildtree(1,h,1,w);
        for(int i = 1; i<=n; i++)
        {
            scanf("%d",&k);
            if(a[1].n>=k)//如果這個公告沒有超出公告板的長度,那麼才能放入
            {
                update(1,k);
                printf("%d\n",ans);
            }
            else
                printf("-1\n");
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章