【知识】CDQ 分治!
CDQ 分治!
统计 \((a,b,c)\) 满足一定大小关系的对数。
首先排序解决掉第一维。
第二维考虑分治,对于目前要处理的区间 \([l,r]\),记 \(mid=\lfloor \frac{l+r}{2}\rfloor\)。
满足条件的点对 \((p,q)\) 如果都在左区间或右区间,递归处理。
否则,考虑双指针。我们记左区间的指针为 \(j\) ,右区间的指针为 \(i\) 。
对于每一个 \(i\) ,我们让 \(j\) 右移,直到找到第一个 \(j\) ,满足 \(b_j>b_i\) ,那么对于 \(x\in[l,j-1]\) 均有 \(b_i\geq b_x\) 。
然后考虑树状数组解决第三维。
对于元素 \(x\in[l,j-1]\) ,我们把属性 \(c\) 值放入树状数组中,只需查询一下 \(query(c_i)\) 就可以找到满足 \(c_i\geq c_x\) 的个数了。
#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
#define rd rd()
void wt(int x){
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
wt(x / 10);
putchar(x % 10 + '0');
return;
}
void wt(char x){
putchar(x);
}
void wt(int x, char k){
wt(x),putchar(k);
}
namespace Star_F{
const int N = 100005, M = 200005;
int n, m;
struct node{
int a, b, c, s, res;
bool operator<(const node& t) const{
if(a!=t.a)
return a < t.a;
if(b!=t.b)
return b < t.b;
return c < t.c;
}
bool operator==(const node& t) const{
return a == t.a && b == t.b && c == t.c;
}
} q[N], w[N];
int tr[M], ans[N];
int low(int x){
return x & -x;
}
void add(int x,int v){
for (int i = x; i < M;i+=low(i))
tr[i] += v;
}
int query(int x){
int res = 0;
for (int i = x; i;i-=low(i))
res += tr[i];
return res;
}
void merge_sort(int l,int r){
if(l>=r)
return;
int mid = l + r >> 1;
merge_sort(l, mid), merge_sort(mid + 1, r);
int i = l, j = mid + 1, k = 0;
while (i <= mid && j <= r)
if (q[i].b <= q[j].b) add(q[i].c, q[i].s), w[k ++ ] = q[i ++ ];
else q[j].res += query(q[j].c), w[k ++ ] = q[j ++ ];
while (i <= mid) add(q[i].c, q[i].s), w[k ++ ] = q[i ++ ];
while (j <= r) q[j].res += query(q[j].c), w[k ++ ] = q[j ++ ];
for (i = l; i <= mid; i ++ ) add(q[i].c, -q[i].s);
for (i = l, j = 0; j < k; i ++, j ++ ) q[i] = w[j];
}
void Main(){
cin >> n >> m;
for (int i = 0; i < n;i++){
int a, b, c;
cin >> a >> b >> c;
q[i] = {a, b, c, 1};
}
sort(q, q + n);
int k = 1;
for (int i = 1; i < n;i++)
if(q[i]==q[k-1])
q[k - 1].s++;
else
q[k++] = q[i];
merge_sort(0, k - 1);
for (int i = 0; i < k;i++)
ans[q[i].res + q[i].s - 1] += q[i].s;
for (int i = 0; i < n; i++)
cout << ans[i] << endl;
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ClockA;
int T=1;
// T=rd;
while(T--) Star_F::Main();
// ClockB;
return 0;
}
P3755 CQOI2017 老C的任务
首先明显可以差分。
把给定点的 \(id\) 设为 0,查询点的 \(id\) 设为 \(1\)。
可以发现,对 \((i,j)\) 有贡献的一定要满足:
- \(x\le i, \ \ y \ \le j, \ \ \ id<1\)
满足三位偏序,cdq 分治即可。
因为第三维只有 \(0\) 或 \(1\),所以无需树状数组,用一个变量记录即可。
#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
#define rd rd()
void wt(int x){
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
wt(x / 10);
putchar(x % 10 + '0');
return;
}
void wt(char x){
putchar(x);
}
void wt(int x, char k){
wt(x),putchar(k);
}
namespace Star_F{
const int N = 500005;
int n,m;
struct node{
int x, y, z, p, id, sign;
ll sum;
bool operator<(const node& a) const{
if(x!=a.x)
return x < a.x;
if(y!=a.y)
return y < a.y;
return z < a.z;
}
} q[N], w[N];
ll ans[N];
void merge_sort(int l,int r){
if(l>=r)
return;
int mid = l + r >> 1;
merge_sort(l, mid), merge_sort(mid + 1, r);
int i = l, j = mid + 1, k = 0;
ll sum = 0;
while (i <= mid && j <= r){
if(q[i].y<=q[j].y)
sum += !q[i].z * q[i].p, w[k++] = q[i++];
else
q[j].sum += sum, w[k++] = q[j++];
}
while(i<=mid)
sum += !q[i].z * q[i].p, w[k++] = q[i++];
while(j<=r)
q[j].sum += sum, w[k++] = q[j++];
for (int i = l, j = 0; j < k;i++,j++)
q[i] = w[j];
}
void Main(){
cin >> n >> m;
for (int i = 0; i < n;i++){
int x, y, p;
cin >> x >> y >> p;
q[i] = {x, y, 0, p};
}
int k = n;
for (int i = 1; i <= m;i++){
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
q[k++] = {x2, y2, 1, 0, i, 1};
q[k++] = {x1 - 1, y2, 1, 0, i, -1};
q[k++] = {x2, y1 - 1, 1, 0, i, -1};
q[k++] = {x1 - 1, y1 - 1, 1, 0, i, 1};
}
sort(q, q + k);
merge_sort(0, k - 1);
for (int i = 0; i < k;i++)
if(q[i].z)
ans[q[i].id] += q[i].sum * q[i].sign;
for (int i = 1; i <= m;i++)
cout << ans[i] << endl;
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ClockA;
int T=1;
// T=rd;
while(T--) Star_F::Main();
// ClockB;
return 0;
}
P3157 [CQOI2011] 动态逆序对
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010;
int n, m;
struct Data
{
int a, t, res;
}q[N], w[N];
int tr[N], pos[N];
LL ans[N];
int lowbit(int x)
{
return x & -x;
}
void add(int x, int v)
{
for (int i = x; i < N; i += lowbit(i)) tr[i] += v;
}
int query(int x)
{
int res = 0;
for (int i = x; i; i -= lowbit(i)) res += tr[i];
return res;
}
void merge_sort(int l, int r)
{
if (l >= r) return;
int mid = l + r >> 1;
merge_sort(l, mid), merge_sort(mid + 1, r);
int i = mid, j = r;
while (i >= l && j > mid)
if (q[i].a > q[j].a) add(q[i].t, 1), i -- ;
else q[j].res += query(q[j].t - 1), j -- ;
while (j > mid) q[j].res += query(q[j].t - 1), j -- ;
for (int k = i + 1; k <= mid; k ++ ) add(q[k].t, -1);
j = l, i = mid + 1;
while (j <= mid && i <= r)
if (q[i].a < q[j].a) add(q[i].t, 1), i ++ ;
else q[j].res += query(q[j].t - 1), j ++ ;
while (j <= mid) q[j].res += query(q[j].t - 1), j ++ ;
for (int k = mid + 1; k < i; k ++ ) add(q[k].t, -1);
i = l, j = mid + 1;
int k = 0;
while (i <= mid && j <= r)
if (q[i].a <= q[j].a) w[k ++ ] = q[i ++ ];
else w[k ++ ] = q[j ++ ];
while (i <= mid) w[k ++ ] = q[i ++ ];
while (j <= r) w[k ++ ] = q[j ++ ];
for (i = l, j = 0; j < k; i ++, j ++ ) q[i] = w[j];
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i ++ )
{
scanf("%d", &q[i].a);
pos[q[i].a] = i;
}
for (int i = 0, j = n; i < m; i ++ )
{
int a;
scanf("%d", &a);
q[pos[a]].t = j -- ;
pos[a] = -1;
}
for (int i = 1, j = n - m; i <= n; i ++ )
if (pos[i] != -1)
q[pos[i]].t = j -- ;
merge_sort(0, n - 1);
for (int i = 0; i < n; i ++ ) ans[q[i].t] = q[i].res;
for (int i = 2; i <= n; i ++ ) ans[i] += ans[i - 1];
for (int i = 0, j = n; i < m; i ++, j -- ) printf("%lld\n", ans[j]);
return 0;
}