zoukankan      html  css  js  c++  java
  • 计蒜客 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

    就先这样,溜了。

  • 相关阅读:
    Unity调用Android的API实现分享功能<转>
    CG函数
    Android三种播放视频的方式
    Android 对话框(Dialog)大全 建立你自己的对话框
    Android播放本地视频
    Unity与Android的对调
    [Shader]LOGO闪光效果
    Android实现拍照与打开本地图片
    Android位图相关解码操作
    Unity3d生成二维码
  • 原文地址:https://www.cnblogs.com/ZERO-/p/9631937.html
Copyright © 2011-2022 走看看