您的位置:首页 > 其它

fzu2171(线段树成段更新)

2014-04-28 10:59 183 查看
地址:http://acm.fzu.edu.cn/problem.php?pid=2171

Problem 2171 防守阵地 II

Accept: 32    Submit: 116

Time Limit: 3000 mSec    Memory Limit : 32768 KB



 Problem Description

部队中总共有N个士兵,每个士兵有各自的能力指数Xi,在一次演练中,指挥部确定了M个需要防守的地点,指挥部将选择M个士兵依次进入指定地点进行防守任务,获得的参考指数即为M个士兵的能力之和。随着时间的推移,指挥部将下达Q个指令来替换M个进行防守的士兵们,每个参加完防守任务的士兵由于疲惫等原因能力指数将下降1。现在士兵们排成一排,请你计算出每次进行防守的士兵的参考指数。



 Input

输入包含多组数据。

输入第一行有两个整数N,M,Q(1<=N<=100000,1<=M<=1000,1<=Q<=100000),第二行N个整数表示每个士兵对应的能力指数Xi(1<=Xi<=1000)。

接下来Q行,每行一个整数X,表示在原始队列中以X为起始的M个士兵替换之前的士兵进行防守。(1<=X<=N-M+1)

对于30%的数据1<=M,N,Q<=1000。



 Output

输出Q行,每行一个整数,为每次指令执行之后进行防守的士兵参考指数。



 Sample Input

5 3 32 1 3 1 4123



 Sample Output

635

思路:首现用一般的成段更新代码写了下,提交后发现超时。于是改变下策略,在没一次查询中将变化记录下来,如果下一次需要向下查询时就将记录的变化赋予下一段,然后将变化后的值返回给上一段,这样就行了。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct node{
int l,r,sum,pl;
}tree[100001*4];
void build(int l,int r,int k){
tree[k].l=l;
tree[k].r=r;
tree[k].pl=0;
if(l==r){
scanf("%d",&tree[k].sum);
return ;
}
int m=(l+r)/2;
build(l,m,k*2);
build(m+1,r,k*2+1);
tree[k].sum=tree[k*2].sum+tree[k*2+1].sum;
}
int getsum(int l,int r,int k){
if(l<=tree[k].l&&r>=tree[k].r){
tree[k].pl++;  //记录变化
tree[k].sum-=(tree[k].r-tree[k].l+1);
return tree[k].sum+tree[k].r-tree[k].l+1;
}
int m=(tree[k].l+tree[k].r)/2,ans;
if(tree[k].pl){
tree[k*2].sum-=(tree[k].pl*(tree[k*2].r-tree[k*2].l+1));  //将变化赋予下一段
tree[k*2+1].sum-=(tree[k].pl*(tree[k*2+1].r-tree[k*2+1].l+1));
tree[k*2].pl+=tree[k].pl;  //记录变化,需要注意这里是+=
tree[k*2+1].pl+=tree[k].pl;
tree[k].pl=0;
}
if(m>=r)
ans=getsum(l,r,k*2);
else if(m<l)
ans=getsum(l,r,k*2+1);
else
ans=getsum(l,m,k*2)+getsum(m+1,r,k*2+1);
tree[k].sum=tree[k*2].sum+tree[k*2+1].sum;  //变化后的值注意返回
return ans;
}
int main(){
int n,m,q;
while(scanf("%d%d%d",&n,&m,&q)>0){
build(1,n,1);
while(q--){
scanf("%d",&n);
printf("%d\n",getsum(n,n+m-1,1));
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线段树 fzu