P3373 模板 線段樹 2

2021-09-26 05:01:33 字數 4726 閱讀 6754

ac**:

這裡的延遲標記要開兩個,分別記錄加法的值和乘法的值,但是乘法和加法的優先順序不一樣,不規定他們的順序的話會有錯誤,所以可以規定乘法優先,即規定好該結點的值等於該節點的值*父節點的乘法延遲標記的值+父節點加法延遲標記的值*區間長度,即,sum[num * 2] = (sum[num * 2] * add[num].wc + ln * add[num].wj) % mod;這樣的話假如改變wj的數值就只改變wj,改變wc的時候把wc也對應的乘一下就可以了。

#include #include #include #include #include #include #define inf 0x3f3f3f3f

using namespace std;

typedef long long ll;

const int maxn = 100100;

ll n, m, mod;

ll a[maxn];

ll sum[maxn * 4];

struct a

add[maxn * 4];

void pushup(ll n)

//建樹

void build(ll l, ll r, ll num)

ll m = (l + r) / 2;

build(l, m, num * 2);

build(m + 1, r, num * 2 + 1);

pushup(num);

return;

}void pushdown(ll num, ll ln, ll rn)

return;

}void update(ll op, ll l, ll r, ll c, ll l, ll r, ll num)

if(op==-1)

return;

}ll m = (l + r) / 2;

pushdown(num, m - l + 1, r - m); //下推標記

if (l <= m)

update(op, l, r, c, l, m, num * 2);

if (r >= m + 1)

update(op, l, r, c, m + 1, r, num * 2 + 1);

pushup(num);

return;

}//區間查詢 查詢區間 l-r

ll query(ll l, ll r, ll l, ll r, ll num)

ll m = (l + r) / 2;

pushdown(num, m - l + 1, r - m);

ll ans = 0;

if (l <= m)

ans += query(l, r, l, m, num * 2);

if (r >= m + 1)

ans += query(l, r, m + 1, r, num * 2 + 1);

return ans%mod;

}int main()

ll x, y, k, z;

scanf("%lld %lld %lld", &n, &m, &mod);

for (int i = 1; i <= n;i++)

scanf("%lld", &a[i]);

build(1, n, 1);

while (m--)

else if(z==2)

else if(z==3)

}return 0;

}

剛開始的思路也是開兩個延遲標記分別記錄,然後因為沒想到怎麼處理乘法和加法的優先順序問題,所以乾脆直接推下去算了(如果給該節點標記乘法延遲標記的時候發現該結點已經存在加法的延遲標記,就把加法的延遲標記推下去(這裡是乙個遞迴的過程),再標記乘法的延遲標記),這樣就保證了乙個節點只會存在一種延遲標記,但是他t了。。

t的**:

#include #include #include #include #include #include #define inf 0x3f3f3f3f

using namespace std;

typedef long long ll;

const int maxn = 100100;

ll n, m, mod;

ll a[maxn];

ll sum[maxn * 4];

struct a

add[maxn * 4];

void pushup(ll n)

//建樹

void build(ll l, ll r, ll num)

ll m = (l + r) / 2;

build(l, m, num * 2);

build(m + 1, r, num * 2 + 1);

pushup(num);

return;

}void pushdown(ll num, ll ln, ll rn, ll l, ll r)

if (add[num * 2 + 1].flag != 0)

add[num * 2].wj = add[num * 2].wj % mod + add[num].wj % mod;

add[num * 2 + 1].wj = add[num * 2 + 1].wj % mod + add[num].wj % mod;

add[num * 2].flag = 1;

add[num * 2 + 1].flag = 1;

sum[num * 2] = sum[num * 2] % mod + ((add[num].wj % mod) * (ln % mod)) % mod;

sum[num * 2 + 1] = sum[num * 2 + 1] % mod + ((add[num].wj % mod) * (rn % mod)) % mod;

add[num].flag = 0;

add[num].wj = 0;

}if (add[num].flag==-1)

if (add[num * 2 + 1].flag != 0)

add[num * 2].wc = ((add[num * 2].wc % mod) * (add[num].wc % mod)) % mod;

add[num * 2 + 1].wc = ((add[num * 2 + 1].wc % mod) * (add[num].wc % mod)) % mod;

add[num * 2].flag = -1;

add[num * 2 + 1].flag = -1;

sum[num * 2] = ((sum[num * 2] % mod) * (add[num].wc % mod)) % mod;

sum[num * 2 + 1] = ((sum[num * 2 + 1] % mod) * (add[num].wc % mod)) % mod;

add[num].flag = 0;

add[num].wc = 1;

}return;

}void update(ll op, ll l, ll r, ll c, ll l, ll r, ll num)

sum[num] =((sum[num]%mod) + ( c * (r - l + 1) )%mod)%mod;

add[num].wj = ((add[num].wj % mod) + (c % mod)) % mod;

add[num].flag = op;

return;

}if(op==-1)

sum[num] = ((sum[num] % mod) * (c % mod)) % mod;

add[num].wc = ((add[num].wc % mod) * (c % mod)) % mod;

add[num].flag = op;

return;

}return;

}ll m = (l + r) / 2;

pushdown(num, m - l + 1, r - m, l, r); //下推標記

if (l <= m)

update(op, l, r, c, l, m, num * 2);

if (r >= m + 1)

update(op, l, r, c, m + 1, r, num * 2 + 1);

pushup(num);

return;

}//區間查詢 查詢區間 l-r

ll query(ll l, ll r, ll l, ll r, ll num)

ll m = (l + r) / 2;

pushdown(num, m - l + 1, r - m, l, r);

ll ans = 0;

if (l <= m)

ans += query(l, r, l, m, num * 2);

if (r >= m + 1)

ans += query(l, r, m + 1, r, num * 2 + 1);

return ans%mod;

}int main()

ll x, y, k, z;

scanf("%lld %lld %lld", &n, &m, &mod);

for (int i = 1; i <= n;i++)

scanf("%lld", &a[i]);

build(1, n, 1);

while (m--)

else if(z==2)

else if(z==3)

}return 0;

}

P3373 模板 線段樹2

如題,已知乙個數列,你需要進行下面三種操作 1.將某區間每乙個數乘上x 2.將某區間每乙個數加上x 3.求出某區間每乙個數的和 include include using namespace std const int maxn 100005 int n,m,p long long arr maxn...

P3373 模板 線段樹 2

題目描述 如題,已知乙個數列,你需要進行下面三種操作 1.將某區間每乙個數乘上x 2.將某區間每乙個數加上x 3.求出某區間每乙個數的和 輸入格式 第一行包含三個整數n m p,分別表示該數列數字的個數 操作的總個數和模數。第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。接下來...

P3373 模板 線段樹 2

題目描述 如題,已知乙個數列,你需要進行下面三種操作 1.將某區間每乙個數乘上x 2.將某區間每乙個數加上x 3.求出某區間每乙個數的和 輸入格式 第一行包含三個整數n m p,分別表示該數列數字的個數 操作的總個數和模數。第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。接下來...