GXU - 7D - 区间求和 - 前缀和
https://oj.gxu.edu.cn/contest/7/problem/D
描述
有一個所有元素皆為0的數(shù)組A,有兩種操作:
1 l r x表示將A區(qū)間[l,r]內(nèi)所有數(shù)加上x;
2 l r表示將A區(qū)間[l,r]內(nèi)從左往右數(shù)第i個數(shù)加上i;
給出m個操作,請輸出操作結束后A中的最大值。
輸入
第一行一個整數(shù)m,表示操作的個數(shù)
接下來有m行,表示操作的內(nèi)容,具體格式與題目中一致
0<=m<=10^6
1<=l<=r<=10^6
0<=x<=10^9
輸出
輸出一個整數(shù),表示所有操作之后A中的最大值
思路,差分,難點在于三角形怎么處理。
其實也不難,計算一下有幾個三角形在哪里出現(xiàn)又消失就可以了。當三角形消失的時候解除掉三角形對當前的影響就足夠了。
首先對差分求前綴和可以復原原數(shù)組,這個簡單。
那么對三角形數(shù)量差分求前綴和可以復原每個區(qū)間的三角形的數(shù)量。
發(fā)現(xiàn)每一個三角形會使得前綴和增加1,解除這個三角形的時候就要把它的貢獻一并解除掉。顯然貢獻就是區(qū)間長。
所以這個數(shù)據(jù)結構可以叫做“LD三角形區(qū)間修改前綴和”?
#include<bits/stdc++.h> using namespace std; typedef long long ll;inline ll read() {ll x = 0;bool f = 0;char c;do {c = getchar();if(c == '-')f = 1;} while(c < '0' || c > '9');do {x = (x << 3) + (x << 1) + c - '0';c = getchar();} while(c >= '0' && c <= '9');return f ? -x : x; }inline void _write(ll x) {if(x > 9)_write(x / 10);putchar(x % 10 + '0'); }inline void write(ll x) {if(x < 0) {putchar('-');x = -x;}_write(x);putchar('\n'); }/*--- ---*/const int MAXM = 1000000; ll df1[MAXM+5]; int df2[MAXM+5];inline void update(int l, int r, ll v) {df1[l]+=v;df1[r+1]-=v; }inline void update2(int l, int r) {df2[l]+=1;df2[r+1]-=1;df1[r+1]-=(r-l+1); }inline ll calc() {ll ans=0;int curd=0;ll curs=0;for(int i=1;i<=MAXM;i++){curd+=df2[i];curs+=curd;curs+=df1[i];if(curs>ans)ans=curs;}return ans; }int main() { #ifdef Yinkufreopen("Yinku.in", "r", stdin);//freopen("Yinku.out","w",stdout); #endif // Yinkuint m=read();while(m--){int op=read(),l=read(),r=read();if(op==1){int x=read();update(l,r,x);}else{update2(l,r);}}write(calc()); }要是少一個數(shù)量級其實可以線段樹:
#include<bits/stdc++.h> using namespace std; typedef long long ll;inline ll read() {ll x = 0;//int f = 0;char c;do {c = getchar();/*if(c == '-')f = 1;*/} while(c < '0' || c > '9');do {x = (x << 3) + (x << 1) + c - '0';c = getchar();} while(c >= '0' && c <= '9');//return f ? -x : x;return x; }inline void _write(int x) {if(x > 9)_write(x / 10);putchar(x % 10 + '0'); }inline void write(int x) {if(x < 0) {putchar('-');x = -x;}_write(x);putchar('\n'); }/*--- ---*/const int MAXM = 1000000; ll a[MAXM + 5]; ll lazy[(MAXM << 2) + 5]; int lazy2[(MAXM << 2) + 5];inline void push_down(int o, int l, int r) {if(lazy[o] || lazy2[o]) {lazy[o << 1] += lazy[o];lazy[o << 1 | 1] += lazy[o];int m = (l + r) >> 1;lazy2[o << 1] += lazy2[o];lazy2[o << 1 | 1] += lazy2[o];lazy[o << 1 | 1] += (m - l + 1) * lazy2[o];lazy[o] = 0;lazy2[o] = 0;} }void build() {memset(a, 0, sizeof(a));memset(lazy, 0, sizeof(lazy));memset(lazy2, 0, sizeof(lazy2)); }void update(int o, int l, int r, int a, int b, ll v) {if(a <= l && r <= b) {lazy[o] += v;return;} else {push_down(o, l, r);int m = (l + r) >> 1;if(a <= m)update(o << 1, l, m, a, b, v);if(b >= m + 1)update(o << 1 | 1, m + 1, r, a, b, v);} }void update2(int o, int l, int r, int a, int b, int h) {//這個區(qū)間底下包含一個高為h的矩形然后上面是一個三角形,最左側恰好有h+1個方塊if(a <= l && r <= b) {lazy[o] += h;lazy2[o]++;return;} else {push_down(o, l, r);int m = (l + r) >> 1;if(a <= m)update2(o << 1, l, m, a, b, h);//左側底下方塊是一樣的if(b >= m + 1)update2(o << 1 | 1, m + 1, r, a, b, h + m - a + 1);//右側多m-a+1個方塊} }void all_pushdown(int o, int l, int r) {if(l == r) {a[l] += lazy[o] + lazy2[o];} else {push_down(o, l, r);int m = (l + r) >> 1;all_pushdown(o << 1, l, m);all_pushdown(o << 1 | 1, m + 1, r);} }int main() { #ifdef Yinkufreopen("Yinku.in", "r", stdin);//freopen("Yinku.out","w",stdout); #endif // Yinku//sieve();build();int m=read();while(m--){int op=read(),l=read(),r=read();if(op==1){int x=read();update(1,1,1000000,l,r,x);}else{update2(1,1,1000000,l,r,0);}}all_pushdown(1,1,1000000);ll maxans=a[1];for(int i=2;i<=1000000;i++){if(a[i]>maxans)maxans=a[i];}printf("%lld\n",maxans); }轉載于:https://www.cnblogs.com/Yinku/p/11073411.html
總結
以上是生活随笔為你收集整理的GXU - 7D - 区间求和 - 前缀和的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。