CCC模板题
Description
为了检验你上午有没有好好听我讲课,于是有了这一题。给你一个数组a[1]~a[N],有q次操作,每次操作有两种类型,第一种询问操作,询问区间[l, r]之间数的和,第二种操作是修改操作,将位置loc的数改为x。对,你没有听错,就是这么简单,简单的话就赶快ac吧。
Input
第一行一个整数T,代表测试数据的组数.
接下来T组测试数据.
每组测试数据第一行两个整数N, q(N, q <= 1e5),分别代表数组a的长度和操作的个数
接下来一行为N个整数,代表数组a
接下来q行,每一行格式为下面两种格式中的一种
1 loc x 将loc位置的数改为x,即a[loc] = x(1 <= loc <= N, 1 <= x <= 1e5)
2 l, r 询问区间[l, r]之间数的和(1 <= l <= r <= N)
Output
对于每组测试数据的询问操作,输出结果
Sample Input
1
5 3
1 2 3 4 5
2 1 2
1 1 100
2 1 2
Sample Output
3
102
HINT
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL maxn=100000;
struct Node
{
int L,R;
int sum;
}Node[maxn<<2];
int a[maxn+5];
void pushUp(int i)//累加
{
int lson = i<<1;
int rson = lson + 1;
Node[i].sum = Node[lson].sum + Node[rson].sum;
}
void build(int i, int l, int r)//建树
{
Node[i].L = l;
Node[i].R = r;
Node[i].sum = 0;
if(l == r)
{
Node[i].sum = a[l];
return;
}
int mid = (l + r)>>1;
build(i<<1, l, mid);
build((i<<1)|1, mid + 1, r);
pushUp(i);
}
void update(int i, int loc, int value)//更新子节点
{
if(Node[i].L == Node[i].R)
{
Node[i].sum = value;
return;
}
int mid = (Node[i].L + Node[i].R)>>1;
if(loc <= mid) update(i<<1, loc, value);
else update((i<<1)|1, loc, value);
pushUp(i);
}
int query(int i, int l, int r)//搜索
{
if(Node[i].L == l && Node[i].R == r)
{
return Node[i].sum;
}
int mid = (Node[i].L + Node[i].R)>>1;
if(r <= mid) return query(i<<1, l, r);
else if(l > mid) return query((i<<1)|1, l, r);
else
{
return query(i<<1, l, mid) + query((i<<1)|1, mid + 1, r);
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
int N,q;
cin>>N>>q;
for(int i=1;i<=N;i++)
{
cin>>a[i];
}
build(1,1,N);
for(int i=1;i<=q;i++)
{
int xx,l,v;
cin>>xx>>l>>v;
if (xx==1)
{
update(1, l, v);
}
if (xx==2)
{
cout<<query(1 , l ,v)<<endl;
}
}
}
return 0;
}
BBB
Description
又到了社团招新的时候,荟园主干道上有很多社团在摆点,averyboy来到了这里,在averyboy心中每个社团有一个满意度。我们可以想象这些社团招新点排成一排,编号从1-N,averyboy又定义了一个区间[l, r]的价值为在这段区间中所有社团满意度的最大值Max和最小值Min的差值即Max - Min.现在averyboy给了你一个问题。一共有q次操作,每次操作有两种类型,第一种类型为查询操作,查询区间[l, r]之间的价值。第二种是更改操作,将第i个社团招新点的满意度更改为x.
Input
第一行一个整数T,代表测试数据组数
接下来T组测试数据,每组测试数据第一行为两个整数N,q(N, q <= 1e5)分别代表社团招新点的个数和操作的个数
接下来一行有N个数,代表N个社团招新点的初始满意度
接下来q行,每一行格式如下面两种中的一种
1 loc x 代表更改操作,将第loc号社团招新点的满意度改为x(1 <= loc <= N, 1 <= x <= 1e5)
2 l r 代表查询操作,查询区间[l, r]的价值(l 1 <= l <= r <= N)
Output
对于每组数据的查询操作,输出结果.
Sample Input
1
5 3
1 2 3 4 5
2 1 5
1 1 2
2 1 5
Sample Output
4
3
HINT
Max与Min必须分开找到,不能单纯寻找Max-Min,不同范围并不恰好连接,Max-Min不具有参考价值
在比较a与b时,a一定会被赋值,b可能未被赋值过
当寻找最大值时,该情况不产生影响
当寻找最小值时,必须排除该种情况,所以我给b赋初值-1,当排除b=-1即可
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL maxn=100000;
struct Node
{
int L,R;
LL Max,Min;
}Node[maxn<<2];
int a[maxn+5];
void pushUp(int i)
{
int lson = i<<1;
int rson = lson + 1;
Node[i].Max=Node[lson].Max>Node[rson].Max?Node[lson].Max:Node[rson].Max;
Node[i].Min=Node[lson].Min<Node[rson].Min?Node[lson].Min:Node[rson].Min;
}
void build(int i, int l, int r)
{
Node[i].L = l;
Node[i].R = r;
Node[i].Max = 0;
Node[i].Min = 0;
if(l == r)
{
Node[i].Max = a[l];
Node[i].Min = a[l];
return;
}
int mid = (l + r)>>1;
build(i<<1, l, mid);
build((i<<1)|1, mid + 1, r);
pushUp(i);
}
void update(int i, int loc, int value)
{
if(Node[i].L == Node[i].R)
{
Node[i].Max = value;
Node[i].Min = value;
return;
}
int mid = (Node[i].L + Node[i].R)>>1;
if(loc <= mid) update(i<<1, loc, value);
else update((i<<1)|1, loc, value);
pushUp(i);
}
int query(int i, int l, int r,int x)//x=1搜最大值,x=2搜最小值
{
if(Node[i].L == l && Node[i].R == r)
{
if(x==1)return Node[i].Max;
else return Node[i].Min;
}
int a=0,b=-1;
int mid = (Node[i].L + Node[i].R)>>1;
if(r <= mid) a=query(i<<1,l,r,x);
else if(l > mid) a=query((i<<1)|1,l,r,x);
else
{
a=query(i<<1, l, mid,x);
b=query((i<<1)|1, mid + 1, r,x);
}
if (x==1) return a>b?a:b;
if (x==2)
if (b!=-1) return a<b?a:b; //找最小值时,当b为初始值-1,说明b未被赋值过,此时Min为a
else return a;
}
int main()
{
int T;
cin>>T;
while(T--)
{
int N,q;
cin>>N>>q;
for(int i=1;i<=N;i++)
{
cin>>a[i];
}
build(1,1,N);
for(int i=1;i<=q;i++)
{
int xx,l,v;
cin>>xx>>l>>v;
if (xx==1&&l<=N)
{
update(1, l, v);
}
if (xx==2&&l<=v)
{
cout<<query(1,l,v,1)-query(1,l,v,2)<<endl;
}
}
}
return 0;
}
DDD
Description
因为聪明的你帮averyboy解决了荟园阿姨给他的问题,他顺利获得了免费的午餐。这次,averyboy再次来到了荟园,还是那个窗口,还是那位阿姨。。。。。。这次,阿姨不想那么容易让他吃到免费的午餐,所以给出了比上次要难的问题。这不,averyboy又来 求助你了。阿姨这次给出的问题如下.给你一个数组a[1]~a[N],然后给你q次操作,每次操作有三种类型,第一种类型是把数组中的某一个数改为x,第二种操作是询问区间[l, r]之间所有奇数的和,如果这个区间没有奇数,输出0,第三种操作是询问区间[l, r]之间所有偶数的和,如果这个区间没有偶数,输出0.
Input
第一行一个整数T,代表测试数据的组数.
接下来T组测试数据.
每组测试数据第一行两个整数N, q(N, q <= 1e5),分别代表数组a的长度和操作的个数
接下来一行为N个整数,代表数组a
接下来q行,每一行格式为下面三种格式中的一种
1 loc x 将loc位置的数改为x,即a[loc] = x(1 <= loc <= N, 1 <= x <= 1e5)
2 l r 询问区间[l, r]之间奇数的和(1 <= l <= r <= N)
3 l r 询问区间[l, r]之间偶数的和(1 <= l <= r <= N)
Output
对于每组测试数据的询问操作,输出结果
Sample Input
1
5 4
1 2 3 4 5
2 1 5
3 1 5
1 1 2
3 1 5
Sample Output
9
6
8
HINT
与模板大同小异,唯一需要注意的是
当进行1操作时
将一个偶数改为一个奇数时,必须将原始的Ousum清0,Jisum再赋值
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL maxn=100000;
struct Node
{
int L,R;
LL Jisum,Ousum;
}Node[maxn<<2];
int a[maxn+5];
void pushUp(int i)
{
int lson = i<<1;
int rson = lson + 1;
Node[i].Jisum = Node[lson].Jisum + Node[rson].Jisum;
Node[i].Ousum = Node[lson].Ousum + Node[rson].Ousum;
}
void build(int i, int l, int r)
{
Node[i].L = l;
Node[i].R = r;
Node[i].Jisum = 0;
Node[i].Ousum = 0;
if(l == r)
{
if (a[l]&1==1) Node[i].Jisum = a[l];
else Node[i].Ousum = a[l];
return;
}
int mid = (l + r)>>1;
build(i<<1, l, mid);
build((i<<1)|1, mid + 1, r);
pushUp(i);
}
void update(int i, int loc, int value)
{
if(Node[i].L == Node[i].R)
{
Node[i].Jisum = 0;//必须重置
Node[i].Ousum = 0;//必须重置
if (value&1==1) Node[i].Jisum = value;
else Node[i].Ousum = value;
return;
}
int mid = (Node[i].L + Node[i].R)>>1;
if(loc <= mid) update(i<<1, loc, value);
else update((i<<1)|1, loc, value);
pushUp(i);
}
int query(int i, int l, int r,int x)
{
if(Node[i].L == l && Node[i].R == r)
{
if(x==2) return Node[i].Jisum;
if(x==3) return Node[i].Ousum;
}
int mid = (Node[i].L + Node[i].R)>>1;
if(r <= mid) return query(i<<1, l, r,x);
else if(l > mid) return query((i<<1)|1, l, r,x);
else
{
return query(i<<1, l, mid,x) + query((i<<1)|1, mid + 1, r,x);
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
int N,q;
cin>>N>>q;
for(int i=1;i<=N;i++)
{
cin>>a[i];
}
build(1,1,N);
for(int i=1;i<=q;i++)
{
int xx,l,v;
cin>>xx>>l>>v;
if (xx==1&&l<=N)
{
update(1, l, v);
}
if (xx==2&&l<=v)
{
cout<<query(1,l,v,xx)<<endl;
}
if (xx==3&&l<=v)
{
cout<<query(1,l,v,xx)<<endl;
}
}
}
return 0;
}