洛谷 2056 采花 - 可持久化线段树 - 树状数组
莫队做法请参见原来的博客 [传送门]
Solution II (主席树,在线)
考虑直接利用主席树统计每个位置对答案的贡献。
查询[l, r]就是在第r棵线段树内查询[l, r]
对于建树,考虑到位置i,和位置(i - 1)的不同在于,位置i可能会导致之前的某个位置对答案的贡献从1变为0,或者某个位置的贡献从0变为1.
至于什么什么情况产生贡献?考虑在[1, r]中,从r向1计数,某个数第二出现的位置就对答案有1的贡献。
然后建树的过程就很显然了。
Code
1 /** 2 * luogu 3 * Problem#2056 4 * Accepted 5 * Time: 736ms 6 * Memory: 88007k 7 */ 8 #include <bits/stdc++.h> 9 using namespace std; 10 typedef bool boolean; 11 typedef pair<int, int> pii; 12 #define fi first 13 #define sc second 14 15 typedef class SegTreeNode { 16 public: 17 int val; 18 SegTreeNode *l; 19 SegTreeNode *r; 20 int belong; 21 22 SegTreeNode(int val = 0):val(val), l(NULL), r(NULL), belong(-1) { } 23 SegTreeNode(int val, SegTreeNode* org):val(val), l(org), r(org), belong(-1) { } 24 25 void pushUp() { 26 val = l->val + r->val; 27 } 28 }SegTreeNode; 29 30 #define Limit 2000000 31 32 SegTreeNode pool[Limit]; 33 SegTreeNode* top = pool; 34 SegTreeNode null = SegTreeNode(0, &null); 35 36 SegTreeNode* newnode() { 37 if(top == pool + Limit) 38 return new SegTreeNode(0, &null); 39 *top = null; 40 return top++; 41 } 42 43 typedef class SegTree { 44 public: 45 int ver; 46 int n; 47 SegTreeNode** rt; 48 49 SegTree() { } 50 SegTree(int n):ver(0), n(n) { 51 rt = new SegTreeNode*[(n + 1)]; 52 for(int i = 0; i <= n; i++) 53 rt[i] = &null; 54 } 55 56 void update(SegTreeNode*& pOld, SegTreeNode*& pNew, int l, int r, int p, int val) { 57 if(pNew->belong != ver + 1) 58 pNew = newnode(), *pNew = *pOld, pNew->belong = ver + 1; 59 pNew->val += val; 60 if(l == r) 61 return; 62 int mid = (l + r) >> 1; 63 if(p <= mid) 64 update(pOld->l, pNew->l, l, mid, p, val); 65 else 66 update(pOld->r, pNew->r, mid + 1, r, p, val); 67 } 68 69 int query(SegTreeNode*& node, int l, int r, int ql, int qr) { 70 if(l == ql && r == qr) 71 return node->val; 72 int mid = (l + r) >> 1, rt = 0; 73 if(ql <= mid) 74 rt += query(node->l, l, mid, ql, (qr < mid) ? (qr) : (mid)); 75 if(qr > mid) 76 rt += query(node->r, mid + 1, r, (ql > mid) ? (ql) : (mid + 1), qr); 77 return rt; 78 } 79 80 SegTreeNode*& operator [] (int pos) { 81 return rt[pos]; 82 } 83 }SegTree; 84 85 int n, c, m; 86 SegTree st; 87 int *ar; 88 89 inline void init() { 90 scanf("%d%d%d", &n, &c, &m); 91 st = SegTree(n); 92 ar = new int[(n + 1)]; 93 for(int i = 1; i <= n; i++) 94 scanf("%d", ar + i); 95 } 96 97 pii *last; 98 inline void solve() { 99 last = new pii[(c + 1)]; 100 fill(last + 1, last + c + 1, pii(-1, -1)); 101 for(int i = 1; i <= n; i++) { 102 boolean aflag = true; 103 if(last[ar[i]].sc != -1) 104 st.update(st[i - 1], st[i], 1, n, last[ar[i]].sc, -1), aflag = false; 105 last[ar[i]].sc = last[ar[i]].fi; 106 last[ar[i]].fi = i; 107 if(last[ar[i]].sc != -1) 108 st.update(st[i - 1], st[i], 1, n, last[ar[i]].sc, 1), aflag = false; 109 if(aflag) 110 st[i] = st[i - 1]; 111 st.ver++; 112 } 113 114 int l, r; 115 while(m--) { 116 scanf("%d%d", &l, &r); 117 printf("%d\n", st.query(st[r], 1, n, l, r)); 118 } 119 } 120 121 int main() { 122 init(); 123 solve(); 124 return 0; 125 }
Solution III (树状数组,离线)
结合一下莫队算法再想想,其实可以读入所有操作,按照右端点排序,在建树的过程中就可以计算答案。
因为没必要把之前的树保留,所以直接用树状数组就好了。
Code
1 /** 2 * luogu & codevs 3 * Problem#2056 & 2365 4 * Accepted & Accepted 5 * Time: 188ms & 3500ms 6 * Memory: 4457k & 53772k 7 */ 8 #include <bits/stdc++.h> 9 using namespace std; 10 typedef bool boolean; 11 typedef pair<int, int> pii; 12 #define fi first 13 #define sc second 14 15 typedef class IndexedTree { 16 public: 17 int s; 18 int* ar; 19 20 IndexedTree() { } 21 IndexedTree(int n):s(n) { 22 ar = new int[(n + 1)]; 23 memset(ar, 0, sizeof(int) * (n + 1)); 24 } 25 26 inline void add(int idx, int val) { 27 for(; idx <= s; idx += (idx & (-idx))) 28 ar[idx] += val; 29 } 30 31 inline int getSum(int idx) { 32 int rt = 0; 33 for(; idx; idx -= (idx & (-idx))) 34 rt += ar[idx]; 35 return rt; 36 } 37 }IndexedTree; 38 39 typedef class Query { 40 public: 41 int l, r, id; 42 43 Query(int l = 0, int r = 0, int id = 0):l(l), r(r), id(id) { } 44 45 boolean operator < (Query b) const { 46 if(r != b.r) return r < b.r; 47 return l < b.l; 48 } 49 }Query; 50 51 int n, c, m; 52 Query *qs; 53 int* ar; 54 IndexedTree it; 55 56 inline void init() { 57 scanf("%d%d%d", &n, &c, &m); 58 it = IndexedTree(n); 59 qs = new Query[(m + 1)]; 60 ar = new int[(n + 1)]; 61 for(int i = 1; i <= n; i++) 62 scanf("%d", ar + i); 63 for(int i = 1; i <= m; i++) 64 scanf("%d%d", &qs[i].l, &qs[i].r), qs[i].id = i; 65 } 66 67 pii *last; 68 int *res; 69 inline void solve() { 70 last = new pii[(c + 1)]; 71 res = new int[(m + 1)]; 72 fill(last + 1, last + c + 1, pii(-1, -1)); 73 sort(qs + 1, qs + m + 1); 74 int p = 1; 75 for(int i = 1, e; i <= n && p <= m; i++) { 76 e = ar[i]; 77 if(last[e].sc != -1) 78 it.add(last[e].sc, -1); 79 last[e].sc = last[e].fi; 80 last[e].fi = i; 81 if(last[e].sc != -1) 82 it.add(last[e].sc, 1); 83 while(qs[p].r == i) 84 res[qs[p].id] = it.getSum(qs[p].r) - it.getSum(qs[p].l - 1), p++; 85 } 86 for(int i = 1; i <= m; i++) 87 printf("%d\n", res[i]); 88 } 89 90 int main() { 91 init(); 92 solve(); 93 return 0; 94 }