ACM-ICPC 2018 徐州赛区网络预赛 H. Ryuji doesn't want to study <<树状数组

题意

维护一个数据结构,使得能进行两种操作

1.查询[l,r]内a[l]×L+a[l+1]×(L1)++a[r1]×2+a[r]之和,L是区间长度。

2.单点更新一个值

思路

线段树和树状数组只能维护区间和,但此题每项有与区间长度相关的权值。

聪明的鸡神想到了三角形法,分别维护(n-i)*a[i]和a[i],在查询时我们算第一个区间和减去第二个区间和乘以(n-r)的差就行了,然后我们神奇的得到了目标和。

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e5+7;
 4 long long tree[2][N];
 5 void add(int x,long long val,int num)
 6 {
 7     while(x<N)
 8     {
 9         tree[num][x]+=val;
10         x+=x&-x;
11     }
12 }
13 long long sum(int x,int num)
14 {
15     long long ret=0;
16     while(x>0)
17     {
18         ret+=tree[num][x];
19         x-=x&-x;
20     }
21     return ret;
22 }
23 int main()
24 {
25     int n,q;
26     while(scanf("%d%d",&n,&q)==2)
27     {
28         memset(tree,0,sizeof(tree));
29         for(int i=1;i<=n;i++)
30         {
31             long long temp;
32             scanf("%lld",&temp);
33             add(i,1LL * temp*(n-i+1),0);
34             add(i,temp,1);
35         }
36         while(q--)
37         {
38             int op;
39             long long a,b;
40             scanf("%d%lld%lld",&op,&a,&b);
41             if(op==1)
42             {
43                 long long ans=0;
44                 ans=sum(b,0)-sum(a-1,0)-(n-b)*(sum(b,1)-sum(a-1,1));
45                 printf("%lld\n",ans);
46             }
47             else{
48                 long long temp;
49                 temp=sum(a,1)-sum(a-1,1);
50                 add(a,-temp+b,1);
51                 add(a,-temp*(n-a+1)+b*(n-a+1),0);
52             }
53         }
54     }
55     return 0;
56 }

后记

鸡神太聪明了!

posted @ 2018-09-12 10:37  computer_luo  阅读(116)  评论(0编辑  收藏  举报