/*
https://www.luogu.com.cn/problem/P1198
*/
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 7;
int m,p;
struct Node {
int l, r; //线段树中每个节点的左端点和右端点
int v;//[l,r]中最大的数
} tr[N];
void pushup(int u) {//由子节点的信息更新所有祖先节点的信息
tr[u].v = max(tr[u << 1].v, tr[u << 1 | 1].v);
}
void build(int u, int l, int r) {
tr[u].l = l;
tr[u].r = r;
if(l == r) return;
int mid = (l + r) / 2;
build(u << 1, l, mid);
//u<<1 u*2
//u<<1|1 u*2+1
build(u << 1 | 1, mid + 1, r);
}
//a[3] -> [3,3]
//修改区间
void modify(int u, int x, int v) {
if(tr[u].l == tr[u].r) tr[u].v=v;
else {
int mid = tr[u].l + tr[u].r >> 1;
if(x <= mid) modify(u << 1, x, v);
else modify(u << 1 | 1, x, v);
pushup(u);
}
}
//询问线段树
int query(int u, int l, int r) {
if(tr[u].l >= l && tr[u].r <= r) return tr[u].v;
//树中的节点已经完全被包含在区间[l,r]中
int mid = tr[u].l + tr[u].r >> 1;
int ans = 0;
if(l <= mid) ans = query(u << 1, l, r);
if(r > mid) ans = max(ans, query(u << 1 | 1, l, r));
return ans;
}
int main() {
int n = 0; //当前数的个数
int last = 0; //上一个数
scanf("%d%d", &m, &p);
build(1, 1, m);
int x;
char op[2];
while(m--) {
scanf("%s%d", op, &x);
if(op[0] == 'Q') {
last = query(1, n - x + 1, n);
printf("%d\n", last);
} else {
modify(1, n + 1, (last + x) % p);
n++;
}
}
return 0;
}
/*
https://www.acwing.com/problem/content/246/
*/
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int n,m;
int w[N];
struct Node
{
int l,r;
int sum;//区间和
int lmax,rmax;//紧靠左端点的最大连续字段和,紧靠右端点的最大连续字段和
int tmax;//最大连续字段和
}tr[N*4];
void pushup(Node &u,Node &l,Node &r)
{
//u是l和r的父结点
u.sum=l.sum+r.sum;
u.lmax=max(l.lmax,l.sum+r.lmax);
u.rmax=max(r.rmax,r.sum+l.rmax);
//查询的区间有可能有三种情况,有可能横跨左右子树
/*
1 查询区间只包含左子树 l.tmax
2 ...右子树 r.max
3 横跨 l.rmax+r.lmax
->父亲的tmax= max{1,2,3};
*/
int res=max(l.tmax,r.tmax);
res=max(res,l.rmax+r.lmax);
u.tmax=res;
}
void pushup(int u)
{
pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}
void build(int u,int l,int r)
{
if(l==r)
{
tr[u]={l,r,w[l],w[l],w[l],w[l]};//开始时sum,lmax等值都是它自身
}
else
{
tr[u].l=l;
tr[u].r=r;
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
}
//从u开始把元区间[x,x]修改成v
void modify(int u,int x,int v)
{
if(tr[u].l==tr[u].r&&tr[u].l==x)
{
//找到元区间
tr[u]={x,x,v,v,v,v};
}
else
{
int mid=tr[u].l+tr[u].r>>1;
if(x<=mid) modify(u<<1,x,v);
else modify(u<<1|1,x,v);
pushup(u);
}
}
Node query(int u,int l,int r)
{
//查询的区间被包含
if(tr[u].l>=l&&tr[u].r<=r) return tr[u];
else
{
int mid=tr[u].l+tr[u].r>>1;
if(r<=mid) //整个区间在左子树
{
return query(u<<1,l,r);
}
else if(l>mid)
{
return query(u<<1|1,l,r);
}
else//横跨左右子树
{
Node left=query(u<<1,l,r);
Node right=query(u<<1|1,l,r);
Node res;
pushup(res,left,right);
return res;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
}
build(1,1,n);
int k,x,y;
while(m--)
{
scanf("%d%d%d",&k,&x,&y);
if(k==1)
{
if(x>y) swap(x,y);
printf("%d\n",query(1,x,y).tmax);
}
else
{
modify(1,x,y);
}
}
return 0;
}
这次培训的心路历程:
懂了但是没完全懂–>莫名其妙地可以理解了。
果然要多写代码。