线段树(种树)

Posted hzoidj123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树(种树)相关的知识,希望对你有一定的参考价值。

                                                                                                                 2017种树

题目描述

2017共有N棵树从0到N-1标号。现要把这些树种在一条直线上,第i棵树的种植位置X[i]如下确定:

X[0] = X[0] MOD L;

X[i] = (X[i-1]*A+B) MOD L。

每棵树种植的费用,是所有标号比它小的树与它的距离之和。2017请你计算各棵树的费用之积,最后对1000000007取余。

输入格式

共五行:

第一行为N

第二行为L

第三行为X[0]

第四行为A

第五行为B

输出格式

总费用

样例

样例输入

5
10
3
1
1

样例输出

180

样例解释:

5棵树的位置分别为: 3, 4, 5, 6, 7.

费用分别为: 1, 3, 6, 10. (从第一棵树开始)

总费用为: 1 × 3 × 6 × 10 = 180.

数据范围与提示

10%的数据:N<=10;

60%的数据:N<=2×10^5;

100%的数据:N,L<=200000; X[0] ,A, B<=10^9.

思路:

思路:用线段树维护的数x小的个数以及比x(第i个数的位置)小的数的和,比x大的树的个数以及比x大的数的和,x的费==(x×比x小的数的个数-比x小的数的和)+(比x大的数的和-x×比x大的数的个数)。

技术图片
 1 #include<cstdio>
 2 const int maxn=200000+10,mod=1000000007;
 3 int tree[maxn<<2],cnt[maxn<<2];
 4 int n,l,xx,a,b;
 5 int ans=1;
 6 void Build(int rt,int l,int r){
 7     if(l==xx&&r==xx){
 8         tree[rt]+=xx;
 9         cnt[rt]++;
10         return ;
11     }
12     int mid=(l+r)>>1;
13     if(xx<=mid) Build(rt<<1,l,mid);
14     else Build(rt<<1|1,mid+1,r);
15     tree[rt]=(tree[rt<<1]+tree[rt<<1|1])%mod;
16     cnt[rt]=cnt[rt<<1]+cnt[rt<<1|1];
17 }
18 int query(int rt,int l,int r,int s,int t){
19     if(s<l) s=l;
20     if(t>r) t=r;
21     if(s==l&&t==r){
22         return tree[rt];
23     }
24     int mid=(l+r)>>1;
25     if(t<=mid) return query(rt<<1,l,mid,s,t)%mod;
26     else if(s>mid) return query(rt<<1|1,mid+1,r,s,t)%mod;
27     else return (query(rt<<1,l,mid,s,t)+query(rt<<1|1,mid+1,r,s,t))%mod;
28 }
29 int query1(int rt,int l,int r,int s,int t){
30     if(s<l) s=l;
31     if(t>r) t=r;
32     if(s==l&&t==r) return cnt[rt];
33     int mid=(l+r)>>1;
34     if(t<=mid) return query1(rt<<1,l,mid,s,t)%mod;
35     else if(s>mid) return query1(rt<<1|1,mid+1,r,s,t)%mod;
36     else return (query1(rt<<1,l,mid,s,t)+query1(rt<<1|1,mid+1,r,s,t))%mod;
37 }
38 void Modify(int rt,int l,int r,int w){
39     if(l==w&&r==w){
40         tree[rt]+=w;
41         cnt[rt]++;
42         return ;
43     }
44     int mid=(l+r)>>1;
45     if(w<=mid) Modify(rt<<1,l,mid,w);
46     else Modify(rt<<1|1,mid+1,r,w);
47     tree[rt]=(tree[rt<<1]+tree[rt<<1|1])%mod;
48     cnt[rt]=cnt[rt<<1]+cnt[rt<<1|1];
49 }
50 void solve(int x){
51     int Min_sum=query(1,0,l-1,0,x);
52     int Min_cnt=query1(1,0,l-1,0,x);
53     int Max_sum=query(1,0,l-1,x,l-1);
54     int Max_cnt=query1(1,0,l-1,x,l-1);
55     int sum=((Min_cnt*x)%mod-Min_sum%mod+Max_sum%mod-(Max_cnt*x)%mod)%mod;
56     ans=(ans*sum)%mod;
57     Modify(1,0,l-1,x);
58 }
59 int main(){
60     scanf("%d%d%d%d%d",&n,&l,&xx,&a,&b);    
61     xx=xx%l;
62     Build(1,0,l-1);
63     for(int i=1;i<n;i++){
64         int x;
65         x=(xx*a+b)%mod;
66         solve(x);
67         xx=x;
68     }
69     printf("%d
",ans);
70     return 0;
71 }
View Code

 


 

以上是关于线段树(种树)的主要内容,如果未能解决你的问题,请参考以下文章

Vijos P1448 校门外的树多解,线段树,树状数组,括号序列法+暴力优化

线段树

线段树个人理解及模板

线段树数据结构详解

校门外的树

二分索引树与线段树分析