樹狀數組 插點問線/插線問點

樹狀數組兩種重要的應用:插點問線(nyoj的士兵殺敵一二)

一.插點問線

http://acm.nyist.net/JudgeOnline/problem.php?pid=116

 
int lowbit(int n)
{
return n & (-n);
}

void add(int i, int plus)
{


while(i <= N)
{
res[i] += plus;
i += lowbit(i);

//插點問線從當前節點先父節點更新,父節點要更新,字節點是不需要更新的;
}
}

int sum(int n)
{
int result = 0;
while(n > 0)
{
result += res[n];
n -= lowbit(n);

//求和從當前節點向下求和
}
return result;
}

int main()
{
int M, i, key, num, plus, start, end;
char str[10];
scanf("%d%d", &N, &M);
for(i = 1; i <= N; ++i)
{
scanf("%d", &key);
add(i, key);
}
while(M--)
{
scanf("%s", str);
if(strcmp(str, "ADD") == 0)
{
scanf("%d%d", &num, &plus);
add(num, plus);
}
else
{
scanf("%d%d", &start, &end);
printf("%d\n", sum(end) - sum(start - 1));
}
}
return  0;
}        


二,插線問點

http://acm.nyist.net/JudgeOnline/problem.php?pid=123


void add(int i, int plus)
{
while(i > 0)
{
dp[i] += plus;
i -= lowbit(i);

//從當前節點向下覆蓋
}
}

int sum(int n)
{
int sum = 0;
while(n <= N)
{
sum +=dp[n];
n += lowbit(n);

//從當前節點向上求和
}
return sum;
}

int main()
{
int T, i, j, first, end, score, res;
char str[10];
scanf("%d%d", &T, &N);
memset(dp, 0, sizeof(dp));
while(T--)
{
scanf("%s", str);
if(strcmp(str, "ADD") == 0)
{
scanf("%d%d%d", &first, &end, &score);
add(first - 1, -score); //dp[]中1到first-1 都減score;
add(end, score);  //dp[]中1到end都加score;

// 操作的結果就是first 到 end 區間上 值被更新;
}
else
{
scanf("%d", &res);
printf("%d\n", sum(res));
}
}
return 0;
}

另一種方法;

add(first,score);//操作的結果是first到N加上score;

add(end+1,-score);//end+1 到 N 減去 score

//所以操作的結果同樣是first 到end 加上了score;

void(int i,int plus)

{

while(i<=N)

{

a[i] += plus;

i  += lowbit(i);

}

}

這裏的問點的操作,比上面的好理解;//這兩種操作的差別的原因是add();的不同;

int sum(int x)

{

int res=0;

while(x>0)

{

res += a[x];

x -= lowbit(x);

}


}

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