计蒜客 1460.Ryuji doesn't want to study-树状数组 or 线段树 (ACM-ICPC 2018 徐州赛区网络预赛 H)

H.Ryuji doesn't want to study

  •  27.34%
  •  1000ms
  •  262144K
 

Ryuji is not a good student, and he doesn't want to study. But there are n books he should learn, each book has its knowledge a[i]a[i].

Unfortunately, the longer he learns, the fewer he gets.

That means, if he reads books from ll to rr, he will get a[l] imes L + a[l+1] imes (L-1) + cdots + a[r-1] imes 2 + a[r]a[l]×L+a[l+1]×(L1)++a[r1]×2+a[r] (LL is the length of [ ll, rr ] that equals to r - l + 1rl+1).

Now Ryuji has qq questions, you should answer him:

11. If the question type is 11, you should answer how much knowledge he will get after he reads books [ ll, rr ].

22. If the question type is 22, Ryuji will change the ith book's knowledge to a new value.

Input

First line contains two integers nn and qq (nn, q le 100000q100000).

The next line contains n integers represent a[i]( a[i] le 1e9)a[i](a[i]1e9) .

Then in next qq line each line contains three integers aa, bb, cc, if a = 1a=1, it means question type is 11, and bb, ccrepresents [ ll , rr ]. if a = 2a=2 , it means question type is 22 , and bb, cc means Ryuji changes the bth book' knowledge to cc

Output

For each question, output one line with one integer represent the answer.

样例输入

5 3
1 2 3 4 5
1 1 3
2 5 0
1 4 5

样例输出

10
8

题目来源

ACM-ICPC 2018 徐州赛区网络预赛

 

 

 

题意很好理解,我有两种方法来写这道题目。

第一种就是树状数组,倒的梯形面积。其实并不是严格意义上的三角形,应该是梯形的面积,但是抽象一下,就是三角形,好理解。

因为下标是从1开始的,所以r+1。横坐标上面的是a数组,下面的是b数组。

代码:

 1 //H-树状数组
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<bitset>
 7 #include<cassert>
 8 #include<cctype>
 9 #include<cmath>
10 #include<cstdlib>
11 #include<ctime>
12 #include<deque>
13 #include<iomanip>
14 #include<list>
15 #include<map>
16 #include<queue>
17 #include<set>
18 #include<stack>
19 #include<vector>
20 using namespace std;
21 typedef long long ll;
22 
23 const double PI=acos(-1.0);
24 const double eps=1e-6;
25 const ll mod=1e9+7;
26 const int inf=0x3f3f3f3f;
27 const int maxn=1e5+10;
28 const int maxm=1e3+10;
29 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
30 
31 ll a[maxn],b[maxn],n,q;
32 
33 int lowbit(int x)
34 {
35     return x&(-x);
36 }
37 
38 void add(ll a[],int x,ll val)
39 {
40     for(int i=x;i<=n;i+=lowbit(i))
41         a[i]+=val;
42 }
43 
44 ll query(ll a[],int x)
45 {
46     ll ans=0;
47     for(int i=x;i>0;i-=lowbit(i))
48         ans+=a[i];
49     return ans;
50 }
51 
52 int main()
53 {
54     cin>>n>>q;
55     for(int i=1;i<=n;i++){
56         ll val;
57         cin>>val;
58         add(a,i,val);//单纯的保存,类似前缀和
59         add(b,i,i*val);//这样保存,减去的时候正好满足条件,*L,*(L-1)。。。
60     }
61     while(q--){
62         ll op,l,r;
63         cin>>op>>l>>r;
64         if(op==2){
65             ll cnt=query(a,l)-query(a,l-1);//单点更新
66             add(a,l,r-cnt);
67             ll ret=query(b,l)-query(b,l-1);//同上
68             add(b,l,l*r-ret);
69         }
70         else{
71             ll cnt=(r+1)*(query(a,r)-query(a,l-1));//先算出横坐标的和,然后*(r+1)就是一个大矩形的面积
72             ll ret=query(b,r)-query(b,l-1);//倒着的梯形面积,(因为从1开始的,所以是梯形不是三角形)
73             cout<<cnt-ret<<endl;
74         }
75     }
76 }

还有一种线段树的方法,线段树的就是左儿子+右儿子+两者包围的矩形的面积。

为了好理解,画成三角形,其实严格意义上是梯形,因为最后一个数是×1,但是为了好理解,画成三角形。

某种意义上是一个个小矩形。

首先我求每一个小的三角形(矩形)就是ans[rt]+sum[rt]*(tmp-len[rt]);

举个例子,只有一个长度的。

sum为单点的值,tmp为总的区间查询长度,len[rt]为当前的区间长度。

怎么求粉色三角形的面积呢?就是我一开始线段树存的大的梯形的面积-紫色平行四边形的面积。

tmp就是总长度为小圈1+小圈2的长度,小圈1的长度就是tmp-len[rt],OK了。

ll query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R){
        int tmp=Len;
        Len-=len[rt];
        return ans[rt]+sum[rt]*(tmp-len[rt]);
    }

    int m=(l+r)>>1;
    ll ret=0;
    if(L<=m) ret+=query(L,R,lson);
    if(R >m) ret+=query(L,R,rson);
    return ret;
}

 然后就是总的面积,就是左儿子+右儿子+左儿子的区间和*右儿子的区间长。

代码睡醒上完课再贴,想睡觉了,头发要紧,哈哈哈哈哈。

直接代码了。

  1 //H-线段树
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<bitset>
  7 #include<cassert>
  8 #include<cctype>
  9 #include<cmath>
 10 #include<cstdlib>
 11 #include<ctime>
 12 #include<deque>
 13 #include<iomanip>
 14 #include<list>
 15 #include<map>
 16 #include<queue>
 17 #include<set>
 18 #include<stack>
 19 #include<vector>
 20 using namespace std;
 21 typedef long long ll;
 22 
 23 const double PI=acos(-1.0);
 24 const double eps=1e-6;
 25 const ll mod=1e9+7;
 26 const int inf=0x3f3f3f3f;
 27 const int maxn=1e5+10;
 28 const int maxm=1e3+10;
 29 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
 30 #define lson l,m,rt<<1
 31 #define rson m+1,r,rt<<1|1
 32 
 33 ll sum[maxn<<2],ans[maxn<<2],len[maxn<<2];
 34 //sum为单点的价值(横坐标),ans为总价值,len为区间长度
 35 int Len;
 36 
 37 void pushup(int rt)
 38 {
 39     ans[rt]= ans[rt<<1]+ans[rt<<1|1]+sum[rt<<1]*len[rt<<1|1];//总价值为左儿子+右儿子+左儿子区间和*右儿子区间长
 40     len[rt]=len[rt<<1]+len[rt<<1|1];
 41     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
 42 }
 43 
 44 void build(int l,int r,int rt)
 45 {
 46     if(l==r){
 47         scanf("%lld",&sum[rt]);
 48         len[rt]=1;
 49         ans[rt]=sum[rt];
 50         return;
 51     }
 52 
 53     int m=(l+r)>>1;
 54     build(lson);
 55     build(rson);
 56     pushup(rt);
 57 }
 58 
 59 ll query(int L,int R,int l,int r,int rt)
 60 {
 61     if(L<=l&&r<=R){
 62         int tmp=Len;
 63         Len-=len[rt];
 64         return ans[rt]+sum[rt]*(tmp-len[rt]);//求小三角形的面积就是大的梯形-平行四边形
 65     }
 66 
 67     int m=(l+r)>>1;
 68     ll ret=0;
 69     if(L<=m) ret+=query(L,R,lson);
 70     if(R >m) ret+=query(L,R,rson);
 71     return ret;
 72 }
 73 
 74 void update(int p,ll val,int l,int r,int rt)//单点更新
 75 {
 76     if(l==r){
 77         sum[rt]=val;
 78         ans[rt]=val;
 79         return;
 80     }
 81 
 82     int m=(l+r)>>1;
 83     if(p<=m) update(p,val,lson);
 84     else     update(p,val,rson);
 85     pushup(rt);
 86 }
 87 
 88 int main()
 89 {
 90     int n, m;
 91     while(~scanf("%d%d",&n,&m)){
 92         build(1,n,1);
 93         while(m--){
 94             int op;
 95             scanf("%d",&op);
 96             if(op==1){
 97                 int l,r;
 98                 scanf("%d%d",&l,&r);
 99                 Len=r-l+1;
100                 printf("%lld
",query(l,r,1,n,1));
101             }
102             else{
103                 int pos;
104                 ll val;
105                 scanf("%d%lld",&pos,&val);
106                 update(pos,val,1,n,1);
107             }
108         }
109     }
110     return 0;
111 }

 还有一份学长过的(啊啊啊啊,好厉害,羞涩,哈哈哈)

  1 #include <stdio.h>
  2 #include <math.h>
  3 #include <string.h>
  4 #include <stdlib.h>
  5 #include <iostream>
  6 #include <sstream>
  7 #include <algorithm>
  8 #include <string>
  9 #include <queue>
 10 #include <map>
 11 #include <vector>
 12 #include <set>
 13 #include <utility>
 14 #include <stack>
 15 #include <list>
 16 using namespace std;
 17 typedef long long LL;
 18 const int N = 1e5+50,M = 1e3+10,inf = 0x3f3f3f3f;
 19 const LL mod = 1e9+7;
 20 const double epx = 1e-6;
 21 const double PI = acos(-1.0);
 22 
 23 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
 24 
 25 LL a[N],sum[M],block[M],pos[N];
 26 int k;
 27 void init(int n)
 28 {
 29     k=sqrt(n);
 30     memset(sum,0,sizeof(sum));
 31     memset(block,0,sizeof(block));
 32     for(int i=1;i<=n;i++)
 33         pos[i]=(i-1)/k+1;
 34     for(int i=1;i<=n/k;i++)
 35     {
 36         int L=(i-1)*k+1;
 37         int R=i*k;
 38         for(int j=L,t=k;j<=R;j++,t--)
 39         {
 40             sum[i]+=a[j];
 41             block[i]+=a[j]*(1LL*t);
 42         }
 43     }
 44 }
 45 void change(int b,int c)
 46 {
 47     int i=pos[b];
 48     a[b]=c;
 49     int L=(i-1)*k+1;
 50     int R=i*k;
 51     sum[i]=0;
 52     block[i]=0;
 53     for(int j=L,t=k;j<=R;j++,t--)
 54     {
 55         sum[i]+=a[j];
 56         block[i]+=a[j]*(1LL*t);
 57     }
 58 }
 59 LL query(int L,int R)
 60 {
 61     LL ans=0;
 62     if(pos[L]==pos[R])
 63     {
 64         for(int i=L,len=(R-L+1);i<=R;i++,len--)
 65         {
 66             ans+=1LL*a[i]*len;
 67         }
 68         return ans;
 69     }
 70     int len=(R-L+1);
 71     for(int i=L;i<=pos[L]*k;i++)
 72     {
 73         ans+=1LL*a[i]*len;len--;
 74     }
 75     for(int i=pos[L]+1;i<pos[R];i++)
 76     {
 77         ans+=block[i];
 78         ans+=1LL*sum[i]*(len-k);
 79         len-=k;
 80     }
 81     for(int i=(pos[R]-1)*k+1;i<=R;i++)
 82     {
 83         ans+=1LL*a[i]*len;len--;
 84     }
 85     return ans;
 86 }
 87 int main()
 88 {
 89     int n,q;
 90     while(~scanf("%d%d",&n,&q))
 91     {
 92         for(int i=1;i<=n;i++)
 93             scanf("%lld",&a[i]);
 94         init(n);
 95         while(q--)
 96         {
 97             int a,b,c;
 98             scanf("%d%d%d",&a,&b,&c);
 99             if(a==1)
100             {
101                 printf("%lld
",query(b,c));
102             }
103             else if(a==2)
104             {
105                 change(b,c);
106             }
107         }
108     }
109     return 0;
110 }
View Code

就先这样,溜了。

原文地址:https://www.cnblogs.com/ZERO-/p/9631937.html