线段树教做人系列(3) HDU 4913
題意及思路看這篇博客就行了,講得很詳細(xì)。
下面是我自己的理解:
如果只有2,沒(méi)有3的話,做法就很簡(jiǎn)單了,只需要對(duì)數(shù)組排個(gè)序,然后從小到大枚舉最大的那個(gè)數(shù)。那么它對(duì)答案的貢獻(xiàn)為(假設(shè)這個(gè)數(shù)排序后的位置是pos)2 ^ (pos - 1) * 2 ^ a[pos]。意思是a[pos]這個(gè)數(shù)必選,其它比它小的數(shù)可選可不選,有2^(pos - 1)種情況?,F(xiàn)在相當(dāng)于變成了一個(gè)二維的問(wèn)題。對(duì)于這種問(wèn)題,我們常見(jiàn)的做法是確定一維,在從前往后掃描某一維時(shí)加上另一維對(duì)答案的貢獻(xiàn)。對(duì)于這個(gè)題,我們可以按數(shù)組b從小到大排序,去計(jì)算a的貢獻(xiàn)。假設(shè)現(xiàn)在掃描到的第pos個(gè)位置(二元組(a[i], b[i])已經(jīng)按數(shù)組b排序),我們考慮來(lái)計(jì)算a[i]對(duì)答案的貢獻(xiàn)。a對(duì)答案的貢獻(xiàn)分為2部分,一部分是之前已經(jīng)出現(xiàn)過(guò)的,小于等于a[i]的值,假設(shè)一共有x個(gè),那么這部分的貢獻(xiàn)為(2 ^ x * 2 ^ a[i]),那么大于a[i]的部分呢?其實(shí)和這個(gè)式子差不多。對(duì)于每個(gè)已經(jīng)出現(xiàn)過(guò),并且大于a[i]的a[j],假設(shè)已經(jīng)出現(xiàn)過(guò)的比a[j]小的數(shù)有y個(gè),那么貢獻(xiàn)為2 ^ (y - 1) * 2 * a[j]。為什么是y - 1? 因?yàn)閍[i]是必選的。通過(guò)觀察,我們可以發(fā)現(xiàn),每一個(gè)a[j]對(duì)答案的貢獻(xiàn),取決當(dāng)前已經(jīng)出現(xiàn)過(guò)的數(shù)中有多少個(gè)比它小的數(shù),所以我們可以這樣維護(hù):在每次插入一個(gè)值時(shí),先詢問(wèn)在這個(gè)數(shù)之前出現(xiàn)了多少個(gè)數(shù)(假設(shè)有x個(gè)),然后插入2 ^ x * 2 ^ a[i],詢問(wèn)[i,n]的區(qū)間和,就是這一階段的答案。之后,要把[i + 1,n]中的數(shù)乘2,因?yàn)樗麄兊那懊娑级嗔艘粋€(gè)a[i]。
代碼:
#include<bits/stdc++.h> #define ls(x) (x << 1) #define rs(x) ((x << 1) | 1) #define LL long long using namespace std; const int maxn = 100010; const LL mod = 1000000007; struct node{int x, y, rank; }; bool cmp1(node x, node y) {return x.x == y.x ? x.y < y.y : x.x < y.x; } bool cmp2(node x, node y) {return x.y == y.y ? x.x < y.x : x.y < y.y; } node a[maxn]; struct SegementTree {LL sum, cnt, lz; }; SegementTree tr[maxn * 4]; LL qpow(LL x, LL y) {LL ans = 1;for (; y; y >>= 1) {if(y & 1) ans = (ans * x) % mod;x = (x * x) % mod;}return ans; } void pushup(int x) {tr[x].sum = (tr[ls(x)].sum +tr[rs(x)].sum) % mod;tr[x].cnt = (tr[ls(x)].cnt + tr[rs(x)].cnt) % mod; } void maintain(int x, int y) {tr[x].sum = (tr[x].sum * qpow(2, y)) % mod;tr[x].lz += y; } void pushdown(int x) {if(tr[x].lz) {if(tr[ls(x)].cnt) maintain(ls(x), tr[x].lz);if(tr[rs(x)].cnt) maintain(rs(x), tr[x].lz);tr[x].lz = 0;} } void build(int x, int l, int r) {if(l == r) {tr[x].sum = tr[x].cnt = 0;return;}int mid = (l + r) >> 1;build(ls(x), l, mid);build(rs(x), mid + 1, r);pushup(x); } void update_cnt(int x, int l, int r, int pos, int y, int z) {if(l == r) {tr[x].cnt = 1;tr[x].sum = (qpow(2, y) * qpow(2, z)) % mod;return;}pushdown(x);int mid = (l + r) >> 1;if(pos <= mid) update_cnt(ls(x), l, mid, pos, y, z);else update_cnt(rs(x), mid + 1, r, pos ,y, z);pushup(x); } void update_sum(int x, int l, int r, int ql, int qr) {if(l >= ql && r <= qr) {tr[x].lz++;tr[x].sum = (tr[x].sum * 2) % mod;return;}pushdown(x);int mid = (l + r) >> 1;if(ql <= mid) update_sum(ls(x), l, mid, ql, qr);if(qr > mid) update_sum(rs(x), mid + 1, r, ql, qr);pushup(x); } LL query_cnt(int x, int l, int r, int ql, int qr) {if(l >= ql && r <= qr) {return tr[x].cnt;}int mid = (l + r) >> 1;pushdown(x);LL ans = 0;if(ql <= mid) ans += query_cnt(ls(x), l, mid, ql, qr);if(qr > mid) ans += query_cnt(rs(x), mid + 1, r, ql, qr);return ans; } LL query_sum(int x, int l, int r, int ql, int qr) {if(l >= ql && r <= qr) {return tr[x].sum;}int mid = (l + r) >> 1;LL ans = 0;pushdown(x);if(ql <= mid) ans += query_sum(ls(x), l, mid, ql, qr);if(qr > mid) ans += query_sum(rs(x), mid + 1, r, ql, qr);return ans % mod; } int main() {int n;while(~scanf("%d", &n)) {for (int i = 1; i <= n; i++) {scanf("%d%d", &a[i].x, &a[i].y);}sort(a + 1, a + 1 + n, cmp1);for (int i = 1; i <= n; i++) {a[i].rank = i;}sort(a + 1, a + 1 + n, cmp2);build(1, 1, n);LL ans = 0;for (int i = 1; i <= n; i++) {LL tmp = query_cnt(1, 1, n, 1, a[i].rank);update_cnt(1, 1, n, a[i].rank, tmp, a[i].x);ans = (ans + query_sum(1, 1, n, a[i].rank, n) * qpow(3, a[i].y) % mod) % mod;if(a[i].rank != n)update_sum(1, 1, n, a[i].rank + 1, n);}printf("%lld\n", ans);} }
轉(zhuǎn)載于:https://www.cnblogs.com/pkgunboat/p/10550737.html
與50位技術(shù)專家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的线段树教做人系列(3) HDU 4913的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: HNOI2013 游走
- 下一篇: codeforces 922E