線段樹 (更新區間查詢點)Color the ball

Color the ball

Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 23628    Accepted Submission(s): 11484


Problem Description
N個氣球排成一排,從左到右依次編號爲1,2,3....N.每次給定2個整數a b(a <= b),lele便爲騎上他的“小飛鴿"牌電動車從氣球a開始到氣球b依次給每個氣球塗一次顏色。但是N次以後lele已經忘記了第I個氣球已經塗過幾次顏色了,你能幫他算出每個氣球被塗過幾次顏色嗎?
 

Input
每個測試實例第一行爲一個整數N,(N <= 100000).接下來的N行,每行包括2個整數a b(1 <= a <= b <= N)。
當N = 0,輸入結束。
 

Output
每個測試實例輸出一行,包括N個整數,第I個數代表第I個氣球總共被塗色的次數。
 

Sample Input
3 1 1 2 2 3 3 3 1 1 1 2 1 3 0
 

Sample Output
1 1 1 3 2 1
 

Author
8600
 

Source
 

Recommend
LL
 代碼:

#include<iostream>
#include<cstring> add[] sum[] //清零
using namespace std;
typedef long long ll;
#define MAX 100000+10
struct node
{
    ll l,r;
    ll mid() //中點
    {
        return (l+r)>>1;
    }
}num[MAX<<2];
ll sum[MAX<<2],add[MAX<<2]; //一般都向右移動 2
void build(ll l,ll r ,ll rt)  //構建線段樹
{
    num[rt].l=l; //先給線段樹的左右賦值
    num[rt].r=r;
    add[rt]=0;
    if(l==r) //如果要構建的線段樹的左右相等 說明已經建到底了 就跳出
    {
        return ;
    }
    build(l,num[rt].mid(),rt<<1);//左下建樹
    build(num[rt].mid()+1,r,rt<<1|1);//右下建樹
}
void PushDown(ll rt,ll m)//向下擴展
{
    if(add[rt])// 當此時節點有要加的數時 就是有倍數時 此節點左子節點 右子節點 都在原有的基礎上倍數加倍數 總數等於區間長度乘倍數
    {
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        sum[rt<<1]+=add[rt]*(m-(m>>1));
        sum[rt<<1|1]+=add[rt]*(m>>1);
        add[rt]=0;// 最後把現在節點 要增加的數賦0
    }
}
void PushUp(ll rt)// 向上擴展(說明此時節點不是最低層)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];// 此節點的和等於左子節點和右子節點的和
}
void update(ll l,ll r,ll rt)// 更新 此題每更新一次add加一 都是固定的 所以此時就傳了三個參數 一般傳四個
{
    if(num[rt].l==l&&num[rt].r==r) //如果此節點就是要更新的節點
    {
        add[rt]++; //此節點的加倍數+1
        sum[rt]+=(num[rt].r-num[rt].l+1)*1; //此節點的和等於區間長度*1
        return;
    }
// 不滿足時
    PushDown(rt,num[rt].r-num[rt].l+1); // 向下擴展一級
    ll m=num[rt].mid();// 得此時節點的中點
    if(r<=m)
    {
        update(l,r,rt<<1);
    }
    else if(l>m)
    {
        update(l,r,rt<<1|1);
    }
    else
    {
        update(l,m,rt<<1);
        update(m+1,r,rt<<1|1);
    }
    PushUp(rt);// 最後再向push rt一定不是低節點 rt爲要更新節點的上一級或最低節點的上一級
}
ll query(ll l,ll r,ll rt) // 查詢 返回查詢到的總和
{
    if(num[rt].l==l&&num[rt].r==r)// 如果查詢到就返回此時節點的總和
    {
        return sum[rt];
    }
// 如果查詢不到
    PushDown(rt,num[rt].r-num[rt].l+1); //向下擴展一級
    ll res=0;// 聲明累加總和
    ll m=num[rt].mid(); //得中點
    if(r<=m)
    {
        res+=query(l,r,rt<<1);
    }
    else if(l>m)
    {
        res+=query(l,r,rt<<1|1);
    }
    else
    {
        res+=query(l,m,rt<<1);
        res+=query(m+1,r,rt<<1|1);
    }
    return res;
}
int main()
{
    int n;
    while(cin>>n)
    {
        if(n==0)
        {
            break;
        }
        build(1,n,1);
        int m=n;
        while(m--)
        {
            int a,b;
            cin>>a>>b;
            update(a,b,1);
        }
        int i;
        for(i=1;i<n;i++)
        {
            cout<<query(i,i,1)<<" ";
        }
        cout<<query(n,n,1)<<endl;
        memset(add,0,sizeof(add));
        memset(sum,0,sizeof(sum));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章