首页 > 代码库 > 【stoi】2010 国王

【stoi】2010 国王

测评的一天...

放道学校测评(stoi2010某题)题解吧...

嗯,就是这么无聊...

这是T3...

(嗯,T2的高精度和T4的拓扑排序我都不会)...

题目:

网址:没有...

技术分享

技术分享

 

大意:区间加法,求各个数

 

嗯,看到区间,又是T3,肯定是线段树...

再看数据范围——

技术分享

 

...

线段树便开始打了起来...

其实也只是区间求和...

 

思路:线段树区间加法,然后输出时全部扫一遍,遇到根结点输出

 

代码:

技术分享
 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 int sum[800000]={0},add[800000]={0};//嗯,数组开大些 
 5 void xiugai(int rt){
 6     sum[rt]=sum[rt*2]+sum[rt*2+1];
 7 }
 8 void biaoji(int l,int r,int rt){
 9     if(add[rt]){
10         add[rt*2]+=add[rt];
11         add[rt*2+1]+=add[rt];
12         sum[rt*2]+=add[rt]*l;
13         sum[rt*2+1]+=add[rt]*r;
14         add[rt]=0;
15     }
16 }
17 void jia(int x,int y,int c,int l,int r,int rt){
18     if(x<=l&&r<=y){
19         sum[rt]+=(r-l+1)*c;
20         add[rt]+=c;
21         return ;
22     }
23     int m=(l+r)/2;
24     if(x<=m)jia(x,y,c,l,m,rt*2);
25     if(m<y)jia(x,y,c,m+1,r,rt*2+1);
26     xiugai(rt);
27 }
28 void out(int l,int r,int rt){
29     if(l==r){//根结点 
30         printf("%d ",sum[rt]);
31         return ;
32     }
33     int m=(l+r)/2;
34     biaoji(l-m+1,r-m,rt);
35     out(l,m,rt*2);
36     out(m+1,r,rt*2+1);
37 }
38 int main(){
39     int n,m,b,c,cc,ccc;
40     scanf("%d%d",&n,&m);
41     for(b=0;b<m;b++){
42         scanf("%d%d%d",&c,&cc,&ccc);//区间加法 
43         jia(c,cc,ccc,1,n,1);
44     }
45     out(1,n,1);//访问各个根结点逐个输出 
46 }
king

就这样提交上去了...

嗯,A了...

线段树裸题...

 

然而正解...

是另外一种神奇解法...

有点前缀和思想...

copy一下解题报告——

技术分享

说到二重过不了,然而还能捞60分...

其实主要思路就是前缀和...

学老师一样画张图吧(当然不会手画)...

技术分享

首先呢,整个序列都是0

假设下n=5,m=2

第一次增加,1~3加上1,那么根据报告的解法,a[1]+=1,a[4]-=1,也就是得到了那一段序列,而在之后的操作中,是第n个数=第n-1个数+a[n](前缀和思想),因此就现在而论,第1个数是1,第2个数=第(2-1=)1个数+a[2](=0)=1,以此类推,第三个数也会是1,而第4个数a[4]=-1,因此到了第4个数,就会=第(4-1=)3个数+a[4](-1)=0,所以第4个数就是0,第5个数也就会等于0(然而这都是针对第一次增加而言)

第二次增加,3~5加上2,那么还是a[3]+=2,a[6]-=2,因为第6个数不会弄到,因此不用管它,这样的话,就又是一段数列

最后,a[n]=a[n-1]+a[n],用sum代替a[n-1]...

来一重循环,一开始sum=0,a[1]=1,因此第一个数就是1,a[2]=0,因此第二个数也是1,a[3]=2,因此sum+=a[3],所以第三个数等于3,紧接着-1,+0,也就得到了最后的答案1 1 3 2 2

 

神奇解法的代码——

技术分享
 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 int main(){
 5     int n,m,b,c,cc,ccc,sum=0,a[100001]={0};
 6     scanf("%d%d",&n,&m);
 7     for(b=0;b<m;b++){
 8         scanf("%d%d%d",&c,&cc,&ccc);
 9         a[c]+=ccc;
10         a[cc+1]-=ccc;
11     }
12     for(b=1;b<=n;b++){
13         sum+=a[b];
14         printf("%d ",sum);
15     }
16 }
king

嗯,和我又臭又长的代码形成强烈反差对比...

至于其他解法,嗯,本jr都不会...

 

又水了一篇博客...

 

【stoi】2010 国王