以下是我今天解题的题解报告:
[1]数列操作
题目描述
给定n个数列,规定有两种操作,一是修改某个元素,二是求子数列[A,B]的连续和。数列的元素个数最多10万个,询问操作最多10万次。
输入
第一行2个整数n,m(n表示输入n个数列,m表示有m个操作)
第二行输入n个数列。
接下来M行,每更好行有三个数k,a,b(k=0表示求子数列[a,b]的和,k=1表示第a个数列加b)
输出
输出若干行数字,表示每次K=0时对应输出一个子数列[a,b]的连续和。
样例输入
10 5
1 2 3 4 5 6 7 8 9 10
1 1 5
0 1 3
0 4 8
1 7 5
0 4 8
样例输出
11
30
35
题目类型:
树状数组,模拟
思路:
存一个求和的数组把每次求和的值放到数组中去拿空间换时间
#include
#include
#include
#include
#include
#include
typedef unsigned long long ull;
using namespace std;
int main()
{
int n,m,num=0;
int a[100005],sum[100005]={0};
scanf("%d%d",&n,&m);
for(int i = 1 ; i <= n ; i++){
scanf("%d",&a[i]);
}
for(int i = 1 ; i <= m ; i++){
int k,x,y;
scanf("%d%d%d",&k,&x,&y);
if(k==1)a[x]+=y;
else{
num++;
for(int j = x; j <= y ; j++){
sum[num]+=a[j];
}
}
}
for(int i = 1 ; i <= num ; i++){
printf("%d\n",sum[i]);
}
return 0;
}
[2] 数星星Stars
题目描述
天空中有一些星星,这些星星都在不同的位置,每个星星有个坐标。 如果一个星星的左下方(包含正左和正下)有k颗星星,就说这颗星星是k级的.
比如,在下面的例图中,星星5是3级的(1,2,4在它左下)。 星星2,4是1级的。例图中有1个0级,2个1级,1个2级,1个3级的星。
【编程任务】
给定星星的位置,输出各级星星的数目。
给定N个点,定义每个点的等级是在该点左下方(含相等)的点的数目,试统计每个等级有多少个点。(1<=N<=15 000,0<=x<=32 000,0<=y<=32 000)
输入
第一行一个整数N(1<=N<=15 000),表示星星的数目。
接下来N行给出每颗星星的坐标,两个整数x,y。
不会有星星重叠。星星按Y坐标增序给出,Y坐标相同的按X坐标增序给出。
输出
N行,每行一个整数,分别是0级,1级,2级……N-1级的星星的数目
样例输入
5
1 1
5 1
7 1
3 3
5 5
样例输出
1
2
1
1
0
思路:
题意就是给你n个点的坐标,定义每个点的等级是再该点左下的点的数量要求输出各个等级包含的点的个数,
已知的是点的输入顺序,按y值增序给出,y值相同按x值增序给出
知道这个之后就可以用x坐标为基准写树状数组,y坐标单调递增不用管,每次查询的ask( )即为该星星的等级,再用ans数组统计各个等级的个数就可以输出了
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=15010;
const int M=32010;
int n,c[M],ans[M];
struct Node{
int x,y;
}node[N];
void add(int x,int y){
while(x<=M){
c[x]+=y;
x += x&(-x);
}
}
int ask(int x){
int res=0;
while(x>0){
res+=c[x];
x -= x&(-x);
}
return res;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d%d",&node[i].x,&node[i].y);
node[i].x++;
}
for(int i=1;i<=n;i++){
int cnt=ask(node[i].x);
add(node[i].x,1);
ans[cnt]++;
}
for(int i=0;i<n;i++){
cout<<ans[i]<<endl;
}
}
[3] 校门外的树
题目描述
校门外有很多树,如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树。
现有两个操作:
K=1,读入l、r表示在区间[l,r]中种上一种树,每次操作种的树的种类都不同
K=2,读入l,r表示询问l~r之间能见到多少种树。
注意:每个座位都可以重复种树。
输入
第一行n,m表示道路总长为n,共有m个操作
接下来m行为m个操作
输出
对于每个k=2输出一个答案
样例输入
5 4
1 1 3
2 2 5
1 2 4
2 3 5
样例输出
1
2
思路:
竺同学今天主要讲的例题,大致意思就是找树的种类就是把左边节点和右边节点的个数记录下来,求某个区域的树的种类把两者相减就可以得到了,
今天 有一发wa的原因是数组开小 了.
#include
#include
#include
#include
using namespace std;
typedef long long ll;
int n,m;
int s1[100005]={0},s2[100005]={0};
void add(int x,int y,int c[]){
while(x<=n){
c[x]+=y;
x += x&(-x);
}
}
int ask(int x,int c[]){
int res=0;
while(x>0){
res+=c[x];
x -= x&(-x);
}
return res;
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 0 ; i < m ; i++){
int k,l,r;
scanf("%d%d%d",&k,&l,&r);
if(k==1){
add(l,1,s1);
add(r,1,s2);
}
else{
printf("%d\n",ask(r,s1)-ask(l-1,s2));
}
}
}
[4] 清点人数
题目描述
初始时,火车上没有学生;当同学们开始上火车时,年级主任从第一节车厢出发走到最后一节车厢,每节车厢随时都有可能有同学上下。年级主任走到第m节车厢时,他想知道第1到m这m节车厢上一共有多少学生,但是他没有调头往回走的习惯.也就是说每次当他提问时,m总会比前一次大。
输入
第一行两个整数n,k,表示火车共有n节车厢以及k个事件。接下来有k行,按时间先后给出k个事件,每行开头都有一个字母A,B或C,如果字母为A,接下来是一个数m,表示年级主任现在在第m节车厢;如果为B,接下来两个数m,p,表示在第m节车厢有p名学生上车;如果为C,接下来两个数m,p,表示在第m节车厢有p名学生下车。学生总人数不会超过100000。
注意:对于30%的数据,n<=10000,k<=10000 至少有3000个A
对于100%的数据n<=500000,k<=100000. 至少有30000个A
输出
有多少个A就输出多少行,每行一个整数,回答年级主任提出的问题。
样例输入
10 7
A 1
B 1 1
B 3 1
B 4 1
A 2
A 3
A 10
样例输出
0
1
2
3
思路:
这题模板题…卡cin的输入,用scanf输入就能过了
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=5e5+5;
int c[N];
int n,m;
int lowbit(int x){
return x&(-x);
}
void add(int x,int y){
while(x<=n){
c[x]+=y;
x+=lowbit(x);
}
}
int ask(int x){
int res=0;
while(x>0){
res+=c[x];
x-=lowbit(x);
}
return res;
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
char op[1005];
scanf("%s",op);
if(op[0]=='A'){
int a;
scanf("%d",&a);
printf("%d\n",ask(a));
}
else if(op[0]=='B'){
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
}
else{
int a,b;
scanf("%d%d",&a,&b);
add(a,-b);
}
}
return 0;
}