树状数组 1 :单点修改,区间查询
题目描述
输入一个数列A1,A2….An(1<=N<=100000),在数列上进行M(1<=M<=100000)次操作,操作有以下两种:
(1) 格式为C I X,其中C为字符“C”,I和X(1<=I<=N,|X|<=10000)都是整数,表示把把a[I]改为X
(2) 格式为Q L R,其中Q为字符“Q”,L和R表示询问区间为[ L ,R] (1<=L<=R<=N),表示询问A[L]+…+A[R]的值。
输入格式
第一行输入N(1<=N<=100000),表述数列的长度;
接下来N行,每行一个整数(绝对值不超过10000)依次输入每个数;
接下来输入一个整数M(1<=M<=100000),表示操作数量,接下来M行,每行为C I X或者Q L R。
输出格式
对于每个Q L R 的操作输出答案。
input
5
1
2
3
4
5
3
Q 2 3
C 3 9
Q 1 4
output
5
16
数据规模与约定
时间限制:1s
空间限制:256MB
#include<bits/stdc++.h>
using namespace std;
#define N 100010
int n,a[N],c[N],m,l,r;
char ch;
int lowbit(int x){
return x&-x;}
void add(int x,int y){
while(x<=n)c[x]+=y,x+=lowbit(x);}
int work(int x)
{
int sum=0;
while(x>0) sum+=c[x],x-=lowbit(x);
return sum;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];add(i,a[i]);}
cin>>m;
for(int i=1;i<=m;i++)
{
cin>>ch>>l>>r;
if(ch=='C') add(l,r-a[l]),a[l]=r;
else cout<<work(r)-work(l-1)<<endl;
}
return 0;
}
数星星
题目描述
天文学家经常要检查星星的地图,每个星星用平面上的一个点来表示,每个星星都有坐标。我们定义一个星星的“级别”为给定的星星中不高于它并且不在它右边的星星的数目。天文学家想知道每个星星的“级别”。
5
*
4
*
1 2 3
* * *
例如上图,5号星的“级别”是3(1,2,4这三个星星),2号星和4号星的“级别”为1。
给你一个地图,你的任务是算出每个星星的“级别”。
输入格式
输入的第一行是星星的数目N(1<=N<=60000),接下来的N行描述星星的坐标(每一行是用一个空格隔开的两个整数X,Y,0<=X,Y<=32000)。
星星的位置互不相同。星星的描述按照Y值递增的顺序列出,Y值相同的星星按照X值递增的顺序列出。
输出格式
输出包含N行,一行一个数。第i行是第i个星星的“级别”
input
5
1 1
5 1
7 1
3 3
5 5
output
0
1
2
1
3
数据规模与约定
时间限制:1s
空间限制:256MB
#include<bits/stdc++.h>
using namespace std;
#define N 100010
int n,c[N],a,b;
int lowbit(int x){
return x&-x;}
void add(int x,int y){
while(x<32100)c[x]+=y,x+=lowbit(x);}
int work(int x)
{
int sum=0;
while(x) sum+=c[x],x-=lowbit(x);
return sum;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++){
cin>>a>>b;a++,b++;cout<<work(a)<<endl;add(a,1);}
return 0;
}
区间修改单点查询
题目描述
已知一个数列,你需要进行下面两种操作:
1.将某区间每一个数数加上x
2.求出某一个数的值
输入格式
第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。
第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。
接下来M行每行包含2或4个整数,表示一个操作,具体如下:
操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k;
操作2: 格式:2 x 含义:输出第x个数的值。
输出格式
输出包含若干行整数,即为所有操作2的结果。
样例数据
input
5 5
1 5 4 2 3
1 2 4 2
2 3
1 1 5 -1
1 3 5 7
2 4
output
6
10
数据规模与约定
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=8,M<=10
对于70%的数据:N<=10000,M<=10000
对于100%的数据:N<=500000,M<=500000
#include<bits/stdc++.h>
using namespace std;
#define N 1000100
int n,a[N],c[N],m,b,t,x,y,z;
int lowbit(int x){
return x&-x;}
void add(int x,int y){
while(x<=n)c[x]+=y,x+=lowbit(x);}
int work(int x)
{
int sum=0;
while(x>0) sum+=c[x],x-=lowbit(x);
return sum;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
{
scanf("%d",&t);
if(t==1){
scanf("%d%d%d",&x,&y,&z);add(x,z);add(y+1,-z);}
else {
scanf("%d",&x);printf("%d\n",a[x]+work(x));}
}
return 0;
}
打鼹鼠
题目描述
SuperBrother在机房里闲着没事干(再对比一下他的NOIP,真是讽刺啊…),于是便无聊地开始玩“打鼹鼠”…
在这个“打鼹鼠”的游戏中,鼹鼠会不时地从洞中钻出来,不过不会从洞口钻进去(鼹鼠真胆大……)。洞口都在一个大小为n(n<=1024)的正方形中。这个正方形在一个平面直角坐标系中,左下角为(0,0),右上角为(n-1,n-1)。洞口所在的位置都是整点,就是横纵坐标都为整数的点。而SuperBrother也不时地会想知道某一个范围的鼹鼠总数。这就是你的任务。
输入格式
每个输入文件有多行。
第一行,一个数n,表示鼹鼠的范围。
以后每一行开头都有一个数m,表示不同的操作:
m=1,那么后面跟着3个数x,y,k(0<=x,y<n),表示在点(x,y)处新出现了k只鼹鼠;
m=2,那么后面跟着4个数x1,y1,x2,y2(0<=x1<=x2<n,0<=y1<=y2<n),表示询问矩形(x1,y1)-(x2,y2)内的鼹鼠数量;
m=3,表示老师来了,不能玩了。保证这个数会在输入的最后一行。
询问数不会超过10000,鼹鼠数不会超过int。
输出格式
对于每个m=2,输出一行数,这行数只有一个数,即所询问的区域内鼹鼠的个数。
input
4
1 2 2 5
2 0 0 2 3
3
output
5
数据规模与约定
水题一道。 所有数据均为随机生成,包括样例……
时间限制:1s
空间限制:256MB
#include<bits/stdc++.h>
using namespace std;
int ans,n,m,x,y,xx,yy,k,a[2000][2000];
int lowbit(int x){
return x&-x;}
void add(int x,int y,int k)
{
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=n;j+=lowbit(j))
a[i][j]+=k;
}
int work(int x,int y)
{
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
for(int j=y;j>0;j-=lowbit(j))
sum+=a[i][j];
return sum;
}
int main()
{
scanf("%d",&n);
while(1)
{
scanf("%d",&m);
if(m==3) break;
else if(m==1)
{
scanf("%d%d%d",&x,&y,&k);
x++,y++;
add(x,y,k);
}
else
{
scanf("%d%d%d%d",&x,&y,&xx,&yy);
ans=work(xx+1,yy+1)-work(xx+1,y)-work(x,yy+1)+work(x,y);
printf("%d\n",ans);
}
}
return 0;
}
[USACO17JAN]Balanced Photo平衡的照片
题目描述
FJ正在安排他的N头奶牛站成一排来拍照。(1<=N<=100,000)序列中的第i头奶牛的高度是h[i],且序列中所有的奶牛的身高都不同。
就像他的所有牛的照片一样,FJ希望这张照片看上去尽可能好。他认为,如果存在i满足max(Ri,Li)>2*min(Li,Ri),第i头奶牛就是不平衡的。(Li和Ri分别代表第i头奶牛左右两边比她高的数量)。
也就是说,如果Li和Ri中的较大者严格来说是这两个数字中较小者的两倍以上,那么i就是不平衡的。
FJ不希望他有太多的奶牛不平衡,请你帮助FJ计算不平衡的奶牛数量。
输入格式
第一行一个整数N。
接下N行包括H[1]到H[n],每行一个非负整数(不大于1,000,000,000)。
输出格式
一行,一个整数,表示不平衡的奶牛数量。
样例数据
input
7
34
6
23
0
5
99
2
output
3
数据规模与约定
时间限制:1s
空间限制:256MB
#include<bits/stdc++.h>
using namespace std;
#define N 100010
int n,c[N],a[N],z[N],y[N],ans,len,b[N];
int lowbit(int x){
return x&-x;}
int add(int x,int y){
while(x<=n)c[x]+=y,x+=lowbit(x);}
int work(int x)
{
int sum=0;
while(x>0)sum+=c[x],x-=lowbit(x);
return sum;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);b[i]=a[i];}
sort(b+1,b+n+1);
len=unique(b+1,b+n+1)-(b+1);
for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+len+1,a[i])-b;
for(int i=1;i<=n;i++) {
z[i]=i-1-work(a[i]);add(a[i],1);}
memset(c,0,sizeof(c));
for(int i=n;i>=1;i--) {
y[i]=n-i-work(a[i]);add(a[i],1);}
for(int i=1;i<=n;i++)
if(2*min(z[i],y[i])<max(z[i],y[i])) ans++;
cout<<ans;
}
人品累加和
题目描述
人品是必不可少的,人品还是守恒的。每个人的人品都是不同的,并且有正的(选择题可以用骰子全过),也有负的。
jzyz有n (1 <= n <= 100,000)个学生,第i个人的人品值是A_i(-10,000 <= A_i <= 10,000).
jzyz决定重新规划寝室,要让每个寝室的人品和不小于0.寝室的人品和是这个寝室里所有人的人品和。
因为名单是按照学籍号给出的,所以,现在你不能调整学生的顺序,只能按照输入的顺序把学生依次分进各个寝室,当然,为了增加难度,每个寝室的人数可以不同,我们甚至可以把n个学生放在同一个寝室。我们的口号,人品比宿舍重要。
比如现在有4个人,人品分别是2, 3, -3, 1。我们可以按照下面分寝室:
(2 3 -3 1)
(2 3 -3) (1)
(2) (3 -3 1)
(2) (3 -3) (1)
这样保证每个寝室的人品和不小于0.
现在的问题是,如果按照这种原则,有多少种分寝室的方法。当然,方法可能很多,你只需要输出方案数对 1,000,000,009 取余数即可。
输入格式
第一行一个整数n
接下来n行,表示每个学生的人品A_i.
输出格式
一个整数,如题所求的那个余数
input
4
2
3
-3
1
output
4
数据规模与约定
40% n<=1000.
100% 数据如题目描述。
时间限制:1s
空间限制:256MB
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define MOD 1000000009
#define N 100010
int len,c[N],b[N],n,f[N],a[N],ans;
int lowbit(int x){
return x&-x;}
void add(int x,int y){
while(x<=n+1){
f[x]+=y;f[x]%=MOD;x+=lowbit(x);}}
int ask(int x)
{
int c=0;
while(x){
c=(c+f[x])%MOD;x-=lowbit(x);}
return c%MOD;
}
signed main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);c[i]=c[i-1]+a[i];b[i]=c[i];}
sort(b+1,b+2+n);
len=unique(b+1,b+2+n)-(b+1);
for(int i=1;i<=1+n;i++){
c[i]=lower_bound(b+1,b+n+2,c[i])-b;}
add(c[n+1],1);
for(int i=1;i<=n;i++){
ans=ask(c[i])%MOD;add(c[i],ans);}
printf("%lld",ans);
return 0;
}
楼兰图腾
Description
在完成了分配任务之后,西部314来到了楼兰古城的西部。相传很久以前这片土地上(比楼兰古城还早)生活着两个部落,一个部落崇拜尖刀(‘V’),一个部落崇拜铁锹(‘∧’),他们分别用V和∧的形状来代表各自部落的图腾。
西部314在楼兰古城的下面发现了一幅巨大的壁画,壁画上被标记出了N个点,经测量发现这N个点的水平位置和竖直位置是两两不同的。西部314认为这幅壁画所包含的信息与这N个点的相对位置有关,因此不妨设坐标分别为(1,y1),(2,y2),…,(n,yn),其中y1~yn是1到n的一个排列。
西部314打算研究这幅壁画中包含着多少个图腾,其中V图腾的定义如下(注意:图腾的形式只和这三个纵坐标的相对大小排列顺序有关)1 <= i < j < k <= n且yi > yj,yj < yk;
而崇拜∧的部落的图腾被定义为1 <= i < j < k <= n且yi < yj , yj > yk;
西部314想知道,这n个点中两个部落图腾的数目。因此,你需要编写一个程序来求出V的个数和∧的个数。
= = = 精简版说明:
平面上有 N(N≤10^5 ) 个点,每个点的横、纵坐标的范围都是 1~N,任意两个点的横、纵坐标都不相同。
若三个点 (x1,y1),(x2,y2),(x3,y3)(x_1,y_1),(x_2,y_2),(x_3,y_3 )(x1,y1),(x2,y2),(x3,y3) 满足 x1<x2<x3,y1>y2x_1 < x_2 < x_3, y_1 > y_2x1<x2<x3,y1>y2 并且 y3>y2y_3 > y_2y3>y2,则称这三个点构成"v"字图腾。
若三个点 (x1,y1),(x2,y2),(x3,y3)(x_1,y_1),(x_2,y_2),(x_3,y_3 )(x1,y1),(x2,y2),(x3,y3) 满足 x1<x2<x3,y1<y2x_1 < x_2 < x_3, y_1 < y_2x1<x2<x3,y1<y2 并且 y3<y2y_3 < y_2y3<y2,则称这三个点构成"^"字图腾。
求平面上"v"和"^"字图腾的个数。
####Input Format
第一行一个数n
第二行是n个数,分别代表y1,y2……yny_1,y_2……y_ny1,y2……yn
Output Format
两个数
中间用空格隔开
依次为V的个数和∧的个数
Sample Input
5
1 5 3 2 4
Sample Output
3 4
Hint
数据范围约定
10%的数据 n<=600
40%的数据 n<=5000
100%的数据 n<=200000,答案不超过int64
####Limitation
各个测试点1s
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 200010
int n,ans,a[N],r[N],l[N],c[N];
int lowbit(int x) {
return x&-x;}
int ask(int x)
{
int sum=0;
while(x>0) sum+=c[x],x-=lowbit(x);
return sum;
}
void add(int x,int y) {
while(x<=n) c[x]+=y,x+=lowbit(x);}
signed main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
memset(c,0,sizeof(c));
for(int i=n;i;i--) {
r[i]=ask(a[i]-1);add(a[i],1);}
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++) {
l[i]=ask(a[i]-1);add(a[i],1);}
for(int i=1;i<=n;i++) ans+=(i-1-l[i])*(n-i-r[i]);
printf("%lld ",ans);
ans=0;
for(int i=1;i<=n;i++) ans+=(l[i])*r[i];
printf("%lld",ans);
}
A Simple Problem with Integers
题目描述
对于数列 A1A_1A1, A2A_2A2, … , ANA_NAN. 你要进行2个操作:将一个区间的数同加上某个数,输出一段区间的和。
输入格式
第一行2个整数表示数列长度和操作次数. 1 ≤ N,Q ≤ 100000.
第二行为数列 A1, A2, … , AN. -1000000000 ≤ Ai ≤ 1000000000.
接下来的Q行操作:
“C a b c” 表示将 Aa, Aa+1, … , Ab.加上c. -10000 ≤ c ≤ 10000.
“Q a b” 输出区间[a,b]的和。
输出格式
输出所有询问的答案,每行1个。
样例数据
input
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
output
4
55
9
15
数据规模与约定
时间限制:5s
空间限制:128MB
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 100010
int n,m,sum[N],a[N],c[2][N],ans,l,r,d;
int lowbit(int x){
return x&-x;}
void add(int x,int y,int z){
for(;y<=n;y+=lowbit(y))c[x][y]+=z;}
int ask(int x,int y){
int ans=0;for(;y;y-=lowbit(y))ans+=c[x][y];return ans;}
signed main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);sum[i]=sum[i-1]+a[i];}
while(m--)
{
char op[2];
scanf("%s%lld%lld",op,&l,&r);
if(op[0]=='C')
{

最低0.47元/天 解锁文章
1003

被折叠的 条评论
为什么被折叠?



