您的位置:首页 > Web前端 > JavaScript

洛谷Oj-P1198 [JSOI2008]最大数-线段树(单点修改)

2018-04-02 09:29 567 查看
问题描述:

现在请求你维护一个数列,要求提供以下两种操作:

1、 查询操作。

语法:Q L

功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。

限制:L不超过当前数列的长度。(L>=0)

2、 插入操作。

语法:A n

功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾。

限制:n是整数(可能为负数)并且在长整范围内。

注意:初始时数列是空的,没有一个数。

AC代码:

long long st[800010];
void push_up(int node)//取较大值
{
st[node] = max(st[node * 2],st[node * 2 + 1]);
return;
}
void up_date(int node,int l,int r,int a,int b)//单点修改,元素a的值加上b
{
if(l == r)//到达了只代表一个元素的线段树结点(叶子结点)
{
st[node] += b;
return;
}
else
{
int mid = (l + r) / 2;
if(a <= mid)//如果在左边
up_date(node * 2,l,mid,a,b);//就去左边找
else//如果在右边
up_date(node * 2 + 1,mid + 1,r,a,b);//就去右边找
push_up(node);
}
return;
}
long long query(int node,int l,int r,int a,int b)
{
if(a <= l && r <= b)//完全包含,直到递归到完全包含为止
return st[node];
else
{
int mid = (l + r) / 2;
long long ans = -inf;//初始化
if(a <= mid)//如果与左儿子重叠
ans = max(ans,query(node * 2,l,mid,a,b));
if(b >= mid + 1)//如果与右儿子重叠
ans = max(ans,query(node * 2 + 1,mid + 1,r,a,b));
return ans;
}
}
int main()
{
int m,d;
cin >> m >> d;//m个操作,对d取模
int sum_e = 0;//数列中元素的个数,同时也是新数应该放入的位置
int t = 0;//上一次查询的结果
for(int i = 1; i <= m; ++i)
{
char order;
cin >> order;
if(order == 'A')
{
sum_e++;//元素个数+1
int n;
cin >> n;
up_date(1,1,m,sum_e,(n + t) % d);//a[sum_e] = (n + t) % d
}
else
{
int l;
cin >> l;
if(l == 0)//不加一个点MLE一个点WA,加了AC
{
t = 0;
cout << t << endl;
continue;
}
t = query(1,1,m,sum_e - l + 1,sum_e);
cout << t << endl;
}
}
return 0;
}


解决方法:

这道题和一般线段树不一样的地方是数列元素的个数未知,不存在初始化建树的操作,数列的元素是动态添加的。由于最多有m次修改,那么数列的元素最多有m个,于是数列的大小定为m。初始化数列的全部元素为0,动态添加元素可以转换为线段树的单点修改。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: