首先发出题目链接:
链接:https://ac.nowcoder.com/acm/contest/923/C
来源:牛客网
涉及:树状数组
题目如下:
对题目进行归纳:
1.type=1时发糖果的人为tokitsukaze,若从pos开始往后发糖,则后面所有人的糖全部+1,与每个人的位置无关。
2.type=2时发糖果的人为teito,若从pos开始发糖,则第x(x>=pos)个位置的人获得
x
−
p
o
s
+
1
x-pos+1
x−pos+1个糖。
3.type=3时发糖果的人为winterzz1,若从pos开始发糖,则第x(x>=pos)个人获得
(
x
−
p
o
s
+
1
)
2
(x-pos+1)^{2}
(x−pos+1)2个糖,且
(
x
−
p
o
s
+
1
)
2
=
x
2
+
(
2
−
2
∗
p
o
s
)
x
+
p
o
s
2
−
2
∗
p
o
s
+
1
(x-pos+1)^{2}=x^{2}+(2-2*pos)x+pos^{2}-2*pos+1
(x−pos+1)2=x2+(2−2∗pos)x+pos2−2∗pos+1
可以发现,第x个人的糖果都可以由一个多项式来表示:
f
(
x
)
=
A
x
x
2
+
B
x
x
+
C
x
f(x)=A_{x}x^{2}+B_{x}x+C_{x}
f(x)=Axx2+Bxx+Cx
同时还可以发现,每次发糖,都只修改了多项式系数 A x A_{x} Ax, B x B_{x} Bx, C x C_{x} Cx
即:
当type=1时:从pos位置后的所有
C
x
C_{x}
Cx全部加1
当type=2时:从pos位置后的所有
C
x
C_{x}
Cx全部加
(
1
−
p
o
s
)
(1-pos)
(1−pos),所有的
B
x
B_{x}
Bx全部加1
当type=3时:从pos位置后的所有
C
x
C_{x}
Cx全部加
(
p
o
s
2
−
2
∗
p
o
s
+
1
)
(pos^{2}-2*pos+1)
(pos2−2∗pos+1),所有的
B
x
B_{x}
Bx全部加
(
2
−
2
∗
p
o
s
)
(2-2*pos)
(2−2∗pos),所有的
A
x
A_{x}
Ax加1
每一次操作,还需要将每个人的糖果数输出出来;每次修改,都要修改一个区间的所有糖果数。
于是,我们只要维护差分数列就可以实现树状数组区间修改,用三个数组分别维护三个系数 A x A_{x} Ax, B x B_{x} Bx, C x C_{x} Cx
树状数组维护差分序列进行区间修改的操作可以看这个博客
下面是对于题目中type的三种操作,对于的树状数组维护操作代码:
if(type==1){
add(tree[1],1,pos);
}
else if(type==2){
add(tree[1],1-pos,pos);
add(tree[2],1,pos);
}
else{
add(tree[1],1-2*pos%mod+(ll)pos*(ll)pos%mod,pos);//pos是int类型,这里pos*pos可能会爆,所以要强制类型转换一下,然后取模
add(tree[2],2-2*pos%mod,pos);
add(tree[3],1,pos);
}
每一次输出所有人的糖果数,相当于多次单点查询,然后差分数组的前n项和刚好相当于单点查询,第i个人的糖果数是 A i i 2 + B i i + C i A_{i}i^{2}+B_{i}i+C_{i} Aii2+Bii+Ci:
for(i=1;i<=n;i++){
ll sumn=0;
sumn+=sum(tree[1],i)%mod;
sumn+=sum(tree[2],i)%mod*i%mod;
sumn+=sum(tree[3],i)%mod*i%mod*i%mod;
printf("%d ",(sumn+mod)%mod);
}
举个例子:
稍后举
代码如下:
#include <iostream>
#include <cstring>
#define mod (ll)1000000007
using namespace std;
typedef long long ll;
ll tree[4][100005];
int n,m,type,pos;
int lowerbit(int x){
return x&-x;
}
void add(ll tr[],ll z,int v){//树状数组单点修改
int i;
for(i=v;i<=n;i+=lowerbit(i))
tr[i]=(tr[i]+z)%mod;
return;
}
ll sum(ll tr[],int v){//树状数组区间查询
int i;
ll sum=0;
for(i=v;i>0;i-=lowerbit(i))
sum=(sum+tr[i])%mod;
return sum;
}
int main(){
int t,i;
cin>>t;
while(t--){
memset(tree,0,sizeof(tree));//每一次先把树状数组清零
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++){
scanf("%d%d",&type,&pos);
//下面按照三种情况维护系数树状数组
if(type==1){
add(tree[1],1,pos);
}
else if(type==2){
add(tree[1],1-pos,pos);
add(tree[2],1,pos);
}
else{
add(tree[1],1-2*pos%mod+(ll)pos*(ll)pos%mod,pos);
add(tree[2],2-2*pos%mod,pos);
add(tree[3],1,pos);
}
}
for(i=1;i<=n;i++){
ll sumn=0;
//下面求多项式的值
sumn+=sum(tree[1],i)%mod;
sumn+=sum(tree[2],i)%mod*i%mod;
sumn+=sum(tree[3],i)%mod*i%mod*i%mod;
printf("%d ",(sumn+mod)%mod);
}
printf("\n");
}
}