hdu 1166 敵兵佈陣(線段樹-單點更新)

題意有N個兵營,每個兵營都給出了人數ai(下標從1開始),有四種命令,(1)”Addij",表示第i個營地增加j人。(2)“Sub i j”,表示第i個營地減少j人。(3)“Query ij",查詢第i個營地到第j個營地的總人數。(4)”End“,表示命令結束。

有三種操作:詢問區間總和,增加某個兵營的兵的數目,減少某個兵營的兵的數目。實際上也只有兩個。

在更新的時候,每到一個區間就把當前區間的sum增加對應的數目,到達葉子結點是返回。這樣就可以不會回溯去更新父親結點的值。查詢的時候,如果區間完全匹配,直接返回區間的sum值,否則向下尋找,直到完全匹配,然後返回它們的和就可以。這時候,結果裏保存的邊界是它們真正的邊界。

// Time 203ms; Memory 1944K
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1<<17

using namespace std;

int size,n,sum,all[40010];
struct line
{
    int l,r;
    int n;
}a[maxn];

void init()
{
    int i;
    for(n=1;n<size;n<<=1);
    for(i=n;i<2*n;i++) 
    {
        a[i].l=a[i].r=i-n+1;
        a[i].n=0;
    }
    for(i=n-1;i>0;i--)
    {
        a[i].l=a[2*i].l;
        a[i].r=a[2*i+1].r;
        a[i].n=0;
    }
}
void insert(int i,int x,int m)
{
    if(x>=a[i].l && x<=a[i].r) a[i].n+=m;
    if(a[i].l==a[i].r) return;
    int mid=(a[i].l+a[i].r)/2;
    if(x>mid) insert(2*i+1,x,m);
    else insert(2*i,x,m);
}
void find(int x,int y,int i)
{
    if(x==a[i].l && y==a[i].r)
    {
        sum+=a[i].n;
        return;
    }
    if(a[i].l==a[i].r) return;
    int mid=(a[i].l+a[i].r)/2;
    if(x>mid) find(x,y,2*i+1);
    else if(y<=mid) find(x,y,2*i);
    else 
    {
        find(x,mid,2*i);
        find(mid+1,y,2*i+1);
    }
}
int main()
{
    int i,j,k,t,x,y,m;
    char s[7];
    scanf("%d",&t);
    for(i=0;i<t;i++)
    {
        scanf("%d",&size);
        init();
        for(j=0;j<size;j++)
        {
            scanf("%d",&k);
            insert(1,j+1,k);
        }
        k=0;
        while(scanf("%s",s)!=EOF && strcmp(s,"End"))
        {
            if(strcmp(s,"Add")==0)
            {
                scanf("%d%d",&x,&m);
                insert(1,x,m);
            }
            else if(strcmp(s,"Sub")==0)
            {
                scanf("%d%d",&x,&m);
                insert(1,x,-m);
            }
            else 
            {
                scanf("%d%d",&x,&y);
                sum=0;
                find(x,y,1);
                all[k++]=sum;
            }
        }
        printf("Case %d:\n",i+1);
        for(j=0;j<k;j++) printf("%d\n",all[j]);
    }
    return 0;
}

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