題意: 寫一段代碼代替以下的古老程式碼片段。
long long data[250001];void A( int st, int nd ) { for( int i = st; i <= nd; i++ ) data[i] = data[i] + (i - st + 1);}void B( int st, int nd ) { for( int i = st; i <= nd; i++ ) data[i] = data[i] + (nd - i + 1);}void C( int st, int nd, int x ) { for( int i = st; i <= nd; i++ ) data[i] = x;}long long S( int st, int nd ) { long long res = 0; for( int i = st; i <= nd; i++ ) res += data[i]; return res;}
解法: 明顯的線段樹。
下面分析一下操作A:
操作A是讓區間st~nd分別加上1~nd-st+1,那麼我們可以把這個區間增量畫成上面的三角形。我們需要考慮如何把這個增量三角形儲存線上段樹的域裡以供查詢。
我們把三角形劃分成左右兩個部分,那麼左邊仍舊是三角形,右邊變成了一個三角形加矩形(陰影部分),顯然我們只需要再開一個add域,把這個矩形增量儲存在add域裡,那麼我們就完成了將增量三角形劃分到左右子樹的任務。
操作B就是把操作A的三角形反過來,思路同上。
操作C。。這個不解釋了。
於是就變成了一道區間增減,修改的線段樹。
然後就是一些敲代碼時候的細節部分了。敲了一個小時,調了2個小時,ORZ
本人只能跑818MS,膜拜488MS大神。
#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;typedef long long lld;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define ls (rt<<1)#define rs (rt<<1|1)const int MAXN = 250001;int cover[MAXN<<2];int opa[MAXN<<2],opb[MAXN<<2];lld sum[MAXN<<2];lld add[MAXN<<2];lld x;lld cal(int a, int b) {return (lld) (b-a+2) * (b-a+1) / 2;}void PRINT(int l, int r,int rt) { printf("************************\n"); printf("rt = %d\n", rt); printf("l = %d, r = %d\n", l, r); printf("sum = %lld\n", sum[rt]); printf("opa = %d\n", opa[rt]); printf("opb = %d\n", opb[rt]); printf("add = %lld\n", add[rt]); printf("cover = %d\n", cover[rt]); printf("*******************************\n\n");}void pushdown(int l, int r, int rt) { // PRINT(l,r,rt);int m = (l+r)>>1;if(cover[rt] == 1) {add[ls] = add[rs] = 0;opa[ls] = opa[rs] = opb[ls] = opb[rs] = 0;sum[ls] = sum[rs] = 0;cover[ls] = cover[rs] = cover[rt];cover[rt] = 0;}add[ls] += add[rt];add[rs] += add[rt];sum[ls] += (lld)(m-l+1)*add[rt];sum[rs] += (lld)(r-m)*add[rt];add[rt] = 0;opa[ls] += opa[rt];opa[rs] += opa[rt];opb[ls] += opb[rt];opb[rs] += opb[rt];sum[rs] += (lld)(m-l+1)*(r-m)*opa[rt];add[rs] += (lld)(m-l+1)*opa[rt];sum[rs] += (lld)(opa[rt]+opb[rt]) * cal(m+1,r);sum[ls] += (lld)(r-m)*(m-l+1)*opb[rt];add[ls] += (lld)(r-m)*opb[rt];sum[ls] += (lld)(opa[rt]+opb[rt]) * cal(l,m);opa[rt] = opb[rt] = 0;//PRINT(l,m,ls);//PRINT(m+1,r,rs);}void pushup(int l, int r, int rt) {int m = (l+r)>>1;sum[rt] = sum[ls] + sum[rs];}void update(int L, int R, char op, int l, int r, int rt) {if(L<=l && r<=R) { // PRINT(l,r,rt);if(op == 'A') {sum[rt] += (lld)(l-L)*(r-l+1); // printf("sum = %lld\n", sum[rt]);sum[rt] += cal(l,r);//printf("sum = %lld\n", sum[rt]);add[rt] += (lld)(l-L);opa[rt] ++;}else if(op == 'B') {sum[rt] += (lld)(R-r)*(r-l+1);sum[rt] += cal(l,r);add[rt] += (lld)(R-r);opb[rt] ++;}else {sum[rt] = x*(r-l+1);cover[rt] = 1;opa[rt] = opb[rt] = 0;add[rt] = x;}//PRINT(l,r,rt);//printf("l = %d, r = %d\n", l, r);//printf("sum = %lld,opa = %d,opb = %d,add = %lld,cover = %d\n",sum[rt],opa[rt],opb[rt],add[rt],cover[rt]);return ;}int m = (l+r)>>1;pushdown(l,r,rt);if(L<=m) update(L,R,op,lson);if(R> m) update(L,R,op,rson);pushup(l,r,rt);}lld query(int L, int R, int l, int r, int rt) {if(L<=l && r<=R) {return sum[rt];}int m = (l+r)>>1;pushdown(l,r,rt);lld ret = 0;if(L<=m) ret += query(L,R,lson);//printf("ret = %d\n", ret);if(R> m) ret += query(L,R,rson);//printf("ret = %d\n", ret);//PRINT(l,r,rt);return ret;}void build(int rt) {sum[rt] = add[rt] = 0;cover[rt] = 1;opa[rt] = opb[rt] = 0;}int main() {int q;int N = 250000;char s[2];int a,b;while(~scanf("%d", &q)) {build(1);while(q--) {scanf("%s%d%d", s, &a, &b);if(s[0] == 'S') {printf("%lld\n", query(a,b,1,N,1));}else {if(s[0] == 'C') scanf("%lld", &x);update(a,b,s[0],1,N,1);}}}return 0;}