学习链接
BZOJ1935 园丁的烦恼
思路
对于每个查询查分成四个分别进行计数。三维分别为时间、\(x\)、\(y\),分治时间,归并\(x\),树状数组\(y\)。
代码
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cassert> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson rt<<1 #define rson rt<<1|1 #define lowbit(x) x&(-x) #define name2str(name) (#name) #define bug printf("*********\n") #define debug(x) cout<<#x"=["<<x<<"]" <<endl #define FIN freopen("D://Code//in.txt","r",stdin) #define IO ios::sync_with_stdio(false),cin.tie(0) const double eps = 1e-8; const int mod = 1000000007; const int maxn = 500000 + 7; const double pi = acos(-1); const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3fLL; const int MX = 10000007; int n, q, tot; int ans[maxn], tree[MX]; int x, y, xx, yy; struct node { int op, x, y, c, qid; }a[maxn*5]; void add(int x, int val) { while(x < MX) { tree[x] += val; x += lowbit(x); } } int ask(int x) { int ans = 0; while(x) { ans += tree[x]; x -= lowbit(x); } return ans; } bool cmp(node a, node b) { return a.x == b.x ? a.y < b.y : a.x < b.x; } void CDQ(int l, int r) { if(l == r) return; int mid = (l + r) >> 1; CDQ(l, mid); CDQ(mid + 1, r); int ls = l; for(int rs = mid + 1; rs <= r; ++rs) { if(a[rs].op == 2) { for( ; ls <= mid && a[ls].x <= a[rs].x; ++ls) { if(a[ls].op == 1) add(a[ls].y, a[ls].c); } ans[a[rs].qid] += a[rs].c * ask(a[rs].y); } } --ls; while(ls >= l) { if(a[ls].op == 1) add(a[ls].y, -1); --ls; } inplace_merge(a + l, a + mid + 1, a + r + 1, cmp); } int main() { #ifndef ONLINE_JUDGE FIN; #endif scanf("%d%d", &n, &q); for(int i = 1; i <= n; ++i) { scanf("%d%d", &x, &y); ++x, ++y; a[++tot] = {1, x, y, 1, 0}; } for(int i = 1; i <= q; ++i) { scanf("%d%d%d%d", &x, &y, &xx, &yy); ++x, ++y, ++xx, ++yy; a[++tot] = {2, xx, yy, 1, i}; a[++tot] = {2, x - 1, yy, -1, i}; a[++tot] = {2, xx, y - 1, -1, i}; a[++tot] = {2, x - 1, y - 1, 1, i}; } CDQ(1, tot); for(int i = 1; i <= q; ++i) printf("%d\n", ans[i]); return 0; }
BZOJ1176 Mokia
思路
在上面的基础上改成了动态加点,但是处理方式其实是一样的,题目里面的\(s\)是没有用的,注意会爆\(int\)。
代码
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cassert> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson rt<<1 #define rson rt<<1|1 #define lowbit(x) x&(-x) #define name2str(name) (#name) #define bug printf("*********\n") #define debug(x) cout<<#x"=["<<x<<"]" <<endl #define FIN freopen("D://Code//in.txt","r",stdin) #define IO ios::sync_with_stdio(false),cin.tie(0) const double eps = 1e-8; const int mod = 1000000007; const int maxn = 2000000 + 7; const double pi = acos(-1); const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3fLL; int w, tot, id, op, x, y, xx, yy, val; int tree[maxn], ans[maxn]; struct node { int x, y, op, c, id; bool operator < (const node& a) const { return x == a.x ? y < a.y : x < a.x; } }a[maxn]; void add(int x, int val) { while(x <= w) { tree[x] += val; x += lowbit(x); } } int ask(int x) { int ans = 0; while(x) { ans += tree[x]; x -= lowbit(x); } return ans; } void cdq(int l, int r) { if(l == r) return; int mid = (l + r) >> 1; cdq(l, mid), cdq(mid + 1, r); int ls = l, rs = mid + 1; for( ; rs <= r; ++rs) { if(a[rs].op == 2) { for( ; ls <= mid && a[ls].x <= a[rs].x; ++ls) { if(a[ls].op == 1) add(a[ls].y, a[ls].c); } ans[a[rs].id] += a[rs].c * ask(a[rs].y); } } --ls; while(ls >= l) { if(a[ls].op == 1) add(a[ls].y, -a[ls].c); --ls; } inplace_merge(a + l, a + mid + 1, a + r + 1); } int main() { #ifndef ONLINE_JUDGE FIN; #endif scanf("%*d%d", &w); while(1) { scanf("%d", &op); if(op == 3) break; if(op == 1) { scanf("%d%d%d", &x, &y, &val); a[++tot] = {x, y, 1, val, 0}; } else { scanf("%d%d%d%d", &x, &y, &xx, &yy); ++id; a[++tot] = {x - 1, y - 1, 2, 1, id}; a[++tot] = {x - 1, yy, 2, -1, id}; a[++tot] = {xx, y - 1, 2, -1, id}; a[++tot] = {xx, yy, 2, 1, id}; } } cdq(1, tot); for(int i = 1; i <= id; ++i) printf("%d\n", ans[i]); return 0; }
陌上花开
思路
三维偏序,在进行\(cdq\)分治之前需要将相同的进行合并,最后对于相同的花(假设是\(v\)),那么对于\(v\)的等级要加上\(cnt[v]-1\)。三维分别为\(a,b,c\),分治\(a\),归并\(b\),树状数组\(c\)。
代码
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cassert> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson rt<<1 #define rson rt<<1|1 #define lowbit(x) x&(-x) #define name2str(name) (#name) #define bug printf("*********\n") #define debug(x) cout<<#x"=["<<x<<"]" <<endl #define FIN freopen("D://Code//in.txt","r",stdin) #define IO ios::sync_with_stdio(false),cin.tie(0) const double eps = 1e-8; const int mod = 1000000007; const int maxn = 200000 + 7; const double pi = acos(-1); const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3fLL; int n, k, tot; int tree[maxn], ans[maxn]; struct node { int a, b, c, cnt, ans; }tmp[maxn], num[maxn]; bool cmp1(node x, node y) { return x.a != y.a ? x.a < y.a : x.b != y.b ? x.b < y.b : x.c < y.c; } bool cmp2(node x, node y) { return x.b != y.b ? x.b < y.b : x.c < y.c; } void add(int x, int val) { while(x <= k) { tree[x] += val; x += lowbit(x); } } int ask(int x) { int ans = 0; while(x) { ans += tree[x]; x -= lowbit(x); } return ans; } void cdq(int l, int r) { if(l == r) return; int mid = (l + r) >> 1; cdq(l, mid), cdq(mid + 1, r); int ls = l, rs = mid + 1; while(ls <= mid && rs <= r) { if(num[ls].b <= num[rs].b) { add(num[ls].c, num[ls].cnt); ++ls; } else { num[rs].ans += ask(num[rs].c); ++rs; } } while(rs <= r) { num[rs].ans += ask(num[rs].c); ++rs; } --ls; while(ls >= l) { add(num[ls].c, -num[ls].cnt); --ls; } inplace_merge(num + l, num + mid + 1, num + r + 1, cmp2); } int main() { #ifndef ONLINE_JUDGE FIN; #endif scanf("%d%d", &n, &k); for(int i = 1; i <= n; ++i) { scanf("%d%d%d", &tmp[i].a, &tmp[i].b, &tmp[i].c); } sort(tmp + 1, tmp + n + 1, cmp1); num[++tot] = tmp[1]; num[tot].cnt = 1; num[tot].ans = 0; for(int i = 2; i <= n; ++i) { if(tmp[i].a == num[tot].a && tmp[i].b == num[tot].b && tmp[i].c == num[tot].c) { ++num[tot].cnt, num[tot].ans = 0; } else { num[++tot] = tmp[i]; num[tot].cnt = 1; num[tot].ans = 0; } } cdq(1, tot); for(int i = 1; i <= tot; ++i) { ans[num[i].cnt-1+num[i].ans] += num[i].cnt; } for(int i = 0; i < n; ++i) { printf("%d\n", ans[i]); } return 0; }
BZOJ3295 动态逆序对
思路
我们先跑出原序列的逆序对,然后用\(cdq\)来计算出删除这个数逆序对的变化值,三维分别为时间、位置、值,分治时间,归并位置,树状数组值。
代码
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cassert> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson rt<<1 #define rson rt<<1|1 #define lowbit(x) x&(-x) #define name2str(name) (#name) #define bug printf("*********\n") #define debug(x) cout<<#x"=["<<x<<"]" <<endl #define FIN freopen("/home/dillonh/CLionProjects/Dillonh/in.txt","r",stdin) #define IO ios::sync_with_stdio(false),cin.tie(0) const double eps = 1e-8; const int mod = 1000000007; const int maxn = 100000 + 7; const double pi = acos(-1); const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3fLL; int n, m, x, tot; LL sum; int num[maxn], tree[maxn], vis[maxn]; LL ans[maxn]; struct node { int x, tim; }a[maxn], tmp[maxn]; void add(int x, int val, int n) { while(x <= n) { tree[x] += val; x += lowbit(x); } } int ask(int x) { int ans = 0; while(x) { ans += tree[x]; x -= lowbit(x); } return ans; } void cdq(int l, int r) { if(l == r) return; int mid = (l + r) >> 1; cdq(l, mid), cdq(mid + 1, r); int cnt = 0, ls = mid, rs = r; for(; rs >= mid + 1; --rs) { for(; ls >= l && a[ls].x > a[rs].x; --ls) { add(a[ls].tim, 1, m + 1); ++cnt; } if(a[rs].tim != m + 1) ans[a[rs].tim] += cnt - ask(a[rs].tim); } ++ls; while(ls <= mid) { add(a[ls].tim, -1, m + 1); ++ls; } cnt = 0, ls = l, rs = mid + 1; for(; ls <= mid; ++ls) { for(; rs <= r && a[rs].x < a[ls].x; ++rs) { add(a[rs].tim, 1, m + 1); ++cnt; } if(a[ls].tim != m + 1) ans[a[ls].tim] += cnt - ask(a[ls].tim); } --rs; while(rs >= mid + 1) { add(a[rs].tim, -1, m + 1); --rs; } cnt = ls = l, rs = mid + 1; while(ls <= mid && rs <= r) { if(a[ls].x < a[rs].x) { tmp[cnt++] = a[ls++]; } else { tmp[cnt++] = a[rs++]; } } while(ls <= mid) { tmp[cnt++] = a[ls++]; } while(rs <= r) { tmp[cnt++] = a[rs++]; } for(int i = l; i <= r; ++i) a[i] = tmp[i]; } int main() { #ifndef ONLINE_JUDGE FIN; #endif scanf("%d%d", &n, &m); for(int i = 1; i <= n; ++i) { scanf("%d", &num[i]); a[++tot] = {num[i], m + 1}; vis[num[i]] = tot; } for(int i = 1; i <= m; ++i) { scanf("%d", &x); a[vis[x]].tim = i; } for(int i = 1; i <= n; ++i) { sum += i - 1 - ask(num[i]); add(num[i], 1, n); } for(int i = 1; i <= n; ++i) { add(num[i], -1, n); } cdq(1, n); for(int i = 1; i <= m; ++i) { printf("%lld\n", sum); sum -= ans[i]; } return 0; }
HDU5324 Boring Class
思路
三维分别是位置、\(L\)、\(R\),分治位置,归并\(R\),树状数组\(L\)。
由于需要输出字典序最小的方案,因此我们考虑在合并的时候用右边来更新左边的信息,记录每个位置作为\(v_1\)能选出的最大的\(m\)。
代码
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cassert> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson rt<<1 #define rson rt<<1|1 #define lowbit(x) x&(-x) #define name2str(name) (#name) #define bug printf("*********\n") #define debug(x) cout<<#x"=["<<x<<"]" <<endl #define FIN freopen("/home/dillonh/CLionProjects/Dillonh/in.txt","r",stdin) #define IO ios::sync_with_stdio(false),cin.tie(0) const double eps = 1e-8; const int mod = 1000000007; const int maxn = 50000 + 7; const double pi = acos(-1); const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3fLL; int n, sz; vector<int> vec; int L[maxn], R[maxn], tree[maxn], ans[maxn]; struct node { int pos, x, y; bool operator < (const node& a) const { return y > a.y; } }a[maxn]; void add(int x, int val) { while(x <= sz) { tree[x] = max(tree[x], val); x += lowbit(x); } } void del(int x) { while(x <= sz) { tree[x] = 0; x += lowbit(x); } } int ask(int x) { int ans = 0; while(x) { ans = max(ans, tree[x]); x -= lowbit(x); } return ans; } bool cmp(node a, node b) { return a.pos < b.pos; } void cdq(int l, int r) { if(l == r) return; int mid = (l + r) >> 1; cdq(mid + 1, r); sort(a + l, a + mid + 1); sort(a + mid + 1, a + r + 1); int ls = l, rs = mid + 1; for(; ls <= mid; ++ls) { for(; rs <= r && a[rs].y >= a[ls].y; ++rs) { add(a[rs].x, ans[a[rs].pos]); } ans[a[ls].pos] = max(ans[a[ls].pos], ask(a[ls].x) + 1); } --rs; while(rs >= l) { del(a[rs].x); --rs; } sort(a + l, a + mid + 1, cmp); cdq(l, mid); } int main() { #ifndef ONLINE_JUDGE FIN; #endif while(~scanf("%d", &n)) { vec.clear(); for(int i = 1; i <= n; ++i) scanf("%d", &L[i]), a[i].x = L[i], a[i].pos = i, vec.emplace_back(L[i]); for(int i = 1; i <= n; ++i) scanf("%d", &R[i]), a[i].y = R[i], ans[i] = 1; sort(vec.begin(), vec.end()); vec.erase(unique(vec.begin(), vec.end()), vec.end()); for(int i = 1; i <= n; ++i) a[i].x = lower_bound(vec.begin(), vec.end(), a[i].x) - vec.begin() + 1; sz = vec.size(); cdq(1, n); int mx = 0, idx = 1; for(int i = 1; i <= n; ++i) { if(ans[i] > mx) { mx = ans[i]; idx = i; } } int las = L[idx], lst = R[idx]; vec.clear(); vec.emplace_back(idx); for(int i = idx + 1; i <= n; ++i) { if(ans[i] == mx - 1 && L[i] <= las && R[i] >= lst) { mx = ans[i], las = L[i], lst = R[i]; vec.emplace_back(i); } } printf("%d\n", (int)vec.size()); for(int i = 0; i < (int)vec.size(); ++i) { if(i) printf(" "); printf("%d", vec[i]); } printf("\n"); } return 0; }
HDU5126 stars
思路
四维偏序,分别为时间,\(x,y,z\),分治时间和\(x\),归并\(x,y\),树状数组\(z\)。
注意第二个\(cdq\)不能改变第一个的数组位置,在第一个\(cdq\)时需要标记每个数组在该分治中是左边一半还是右边一半,如果不标记的话那么在第二次\(cdq\)时就会忽略时间的关系。
代码
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cassert> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson rt<<1 #define rson rt<<1|1 #define lowbit(x) x&(-x) #define name2str(name) (#name) #define bug printf("*********\n") #define debug(x) cout<<#x"=["<<x<<"]" <<endl #define FIN freopen("D://Code//in.txt","r",stdin) #define IO ios::sync_with_stdio(false),cin.tie(0) const double eps = 1e-8; const int mod = 1000000007; const int maxn = 450000 + 7; const double pi = acos(-1); const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3fLL; vector<int> vec; int t, q, tot, op, x, y, z, xx, yy, zz, sz; int tree[maxn], ans[maxn]; struct node { int x, y, z, op, id, flag, c; }a[maxn], tmp[maxn], pp[maxn]; void add(int x, int val) { while(x <= sz) { tree[x] += val; x += lowbit(x); } } int ask(int x) { int ans = 0; while(x) { ans += tree[x]; x -= lowbit(x); } return ans; } void cdq2(int l, int r) { if(l == r) return; int mid = (l + r) >> 1; cdq2(l, mid), cdq2(mid + 1, r); int ls = l, rs = mid + 1, cnt = l; for(; rs <= r; ++rs) { for(; ls <= mid && tmp[ls].y <= tmp[rs].y; ++ls) { if(tmp[ls].op == 1 && tmp[ls].flag) add(tmp[ls].z, tmp[ls].c); } if(tmp[rs].op == 2 && !tmp[rs].flag) ans[tmp[rs].id] += tmp[rs].c * ask(tmp[rs].z); } --ls; while(ls >= l) { if(tmp[ls].op == 1 && tmp[ls].flag) add(tmp[ls].z, -tmp[ls].c); --ls; } ls = l, rs = mid + 1; while(ls <= mid && rs <= r) { if(tmp[ls].y < tmp[rs].y) { pp[cnt++] = tmp[ls++]; } else if(tmp[ls].y > tmp[rs].y) { pp[cnt++] = tmp[rs++]; } else if(tmp[ls].z <= tmp[rs].z) { pp[cnt++] = tmp[ls++]; } else { pp[cnt++] = tmp[rs++]; } } while(ls <= mid) { pp[cnt++] = tmp[ls++]; } while(rs <= r) { pp[cnt++] = tmp[rs++]; } for(int i = l; i <= r; ++i) tmp[i] = pp[i]; } void cdq1(int l, int r) { if(l == r) return; int mid = (l + r) >> 1; cdq1(l, mid); cdq1(mid + 1, r); int ls = l, rs = mid + 1, cnt = l; while(ls <= mid && rs <= r) { if(a[ls].x < a[rs].x) { tmp[cnt] = a[ls++]; tmp[cnt++].flag = 1; } else if(a[ls].x > a[rs].x) { tmp[cnt] = a[rs++]; tmp[cnt++].flag = 0; } else if(a[ls].y < a[rs].y) { tmp[cnt] = a[ls++]; tmp[cnt++].flag = 1; } else if(a[ls].y > a[rs].y) { tmp[cnt] = a[rs++]; tmp[cnt++].flag = 0; } else if(a[ls].z <= a[rs].z) { tmp[cnt] = a[ls++]; tmp[cnt++].flag = 1; } else { tmp[cnt] = a[rs++]; tmp[cnt++].flag = 0; } } while(ls <= mid) { tmp[cnt] = a[ls++]; tmp[cnt++].flag = 1; } while(rs <= r) { tmp[cnt] = a[rs++]; tmp[cnt++].flag = 0; } for(int i = l; i <= r; ++i) a[i] = tmp[i]; cdq2(l, r); } int main() { #ifndef ONLINE_JUDGE FIN; #endif scanf("%d", &t); while(t--) { tot = 0; vec.clear(); scanf("%d", &q); int cnt = 0; for(int i = 1; i <= q; ++i) { scanf("%d%d%d%d", &op, &x, &y, &z); if(op == 1) a[++tot] = {x, y, z, op, 0, 0, 1}, vec.push_back(z); else { scanf("%d%d%d", &xx, &yy, &zz); ++cnt; a[++tot] = {xx, yy, zz, op, cnt, 0, 1}; a[++tot] = {x - 1, yy, zz, op, cnt, 0, -1}; a[++tot] = {xx, y - 1, zz, op, cnt, 0, -1}; a[++tot] = {xx, yy, z - 1, op, cnt, 0, -1}; a[++tot] = {x - 1, y - 1, zz, op, cnt, 0, 1}; a[++tot] = {x - 1, yy, z - 1, op, cnt, 0, 1}; a[++tot] = {xx, y - 1, z - 1, op, cnt, 0, 1}; a[++tot] = {x - 1, y - 1, z - 1, op, cnt, 0, -1}; vec.push_back(z); vec.push_back(z - 1); vec.push_back(zz); vec.push_back(zz - 1); } } sort(vec.begin(), vec.end()); vec.erase(unique(vec.begin(), vec.end()), vec.end()); sz = vec.size(); for(int i = 1; i <= tot; ++i) { a[i].z = lower_bound(vec.begin(), vec.end(), a[i].z) - vec.begin() + 1; } cdq1(1, tot); for(int i = 1; i <= cnt; ++i) { printf("%d\n", ans[i]); ans[i] = 0; } } return 0; }