盛夏将至,有什么比吉卜力更美好的吗?
img
树状数组训练
楼兰图腾
找左边比他大的,右边比他大的,相乘
类似的也可以求出另一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <bits/stdc++.h> #define int long long using namespace std;const int maxn=2e5 +10 ;int a[maxn],c[maxn],n,ans1,ans2;int ask (int x) { int ret=0 ; for (;x;x-=(x&-x)) ret+=c[x]; return ret; } void add (int x) { for (;x<maxn;x+=(x&-x)) c[x]++; } signed main () { cin>>n; for (int i=1 ;i<=n;i++) { cin>>a[i]; } for (int i=1 ;i<=n;i++){ int prevmn=ask (a[i]-1 ),postmn=a[i]-1 -prevmn; int prevmx=i-prevmn-1 ,postmx=n-a[i]-prevmx; add (a[i]); ans1+=prevmx*postmx,ans2+=prevmn*postmn; } cout<<ans1<<" " <<ans2; }
A Tiny Problem with
intergers
差分即可
差分进行求和就可以得到单点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include <bits/stdc++.h> using namespace std;int a[100001 ],b[100001 ];int n,m;void add (int x,int y) { while (x<=n) { b[x]+=y; x+=x&-x; } } int ask (int x) { int ans=0 ; while (x) { ans+=b[x]; x-=x&-x; } return ans; } int main () { cin>>n>>m; for (int i=1 ;i<=n;i++)cin>>a[i]; while (m--) { char c; cin>>c; if (c=='C' ) { int x,y,d; cin>>x>>y>>d; add (x,d); add (y+1 ,-d); } else { int x; cin>>x; cout<<ask (x)+a[x]<<endl; } } return 0 ; }
A Simple Problem with
Integers
其实用线段树就可以秒了
但为了更好理解树状数组
还是建议用树状数组
由于是区间修改
因此考虑差分
差分数组为b[]
那么区间和就可以表达为如下图的形式
$ _{i=1}x{j=1}ib[j]={i=1}^x(x-i+1)
b[i]=(x+1) {i=1} x b[i]- {i=1} x i b[i]$
因此我们要维护两个树状数组
一个是i*b[i],另一个就是b[i]了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 #include <bits/stdc++.h> using namespace std;int n,m;long long a[100010 ],c0[100010 ],c1[100010 ],sum[100010 ];void add0 (int x,long long y) { while (x<=n) { c0[x]+=y; x+=x&-x; } } void add1 (int x,long long y) { while (x<=n) { c1[x]+=y; x+=x&-x; } } long long ask0 (int x) { long long ans=0 ; while (x) { ans+=c0[x]; x-=x&-x; } return ans; } long long ask1 (int x) { long long ans=0 ; while (x) { ans+=c1[x]; x-=x&-x; } return ans; } int main () { cin>>n>>m; for (int i=1 ;i<=n;i++) { cin>>a[i]; sum[i]=a[i]+sum[i-1 ]; } for (int i=1 ;i<=m;i++) { char c; cin>>c; if (c=='C' ) { long long x,y,d; cin>>x>>y>>d; add0 (x,d); add0 (y+1 ,-d); add1 (x,x*d); add1 (y+1 ,(y+1 )*(-d)); } else { int x,y; cin>>x>>y; long long ans=(sum[y]+(y+1 )*ask0 (y)-ask1 (y))-(sum[x-1 ]+x*ask0 (x-1 )-ask1 (x-1 )); cout<<ans<<endl; } } return 0 ; }
Lost Cows
树状数组+二分
注意每次要消除影响
从后往前计算,因为a[n]是确定的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <bits/stdc++.h> using namespace std;const int maxn = 1e5 + 10 ;int c[maxn];int n;int query (int x) { int res = 0 ; for (; x; x -= x&(-x)) res += c[x]; return res; } void add (int x, int y) { for (;x <= n; x += x & (-x)) c[x] += y; } int a[maxn];int ans[maxn];int main () { cin >> n; add (1 , 1 ); a[1 ] ++; for (int i = 2 ; i <= n ; i ++ ) { cin >> a[i]; a[i] ++; add (i, 1 ); } for (int i = n; i >= 1 ; i -- ) { int l = 1 , r = n + 1 ; while (r - l >= 1 ){ int mid = l + r >> 1 ; if (query (mid) >= a[i]) r = mid; else l = mid + 1 ; } ans[i] = l; add (l, -1 ); } for (int i = 1 ; i <= n; i ++ ) { cout << ans[i] << endl; } return 0 ; }
img