CDQ分治小结
CDQ分治小结
P3810三维偏序(陌上花开)
一道CDQ分治的比较模板又不是模板的问题.
设\(f_i\)表示\(a_j<=a_i\)且\(b_j<=b_i\)且\(c_j<=c_i\)的\(j\)的数量
对于\(d\in[0,n)\)让你求\(f(i) == d\)的数量
其实个人感觉模板的话
还是严格小于比较好做
先来考虑一下严格小于该怎么做
我们先对整体按照\(a_i\)排序,这样的话我们进行的分治就满足了第一个限制
之后我们试想一下,如果要求左区间对于右区间的贡献
我们只需要将两边分别排序
虽然这样两边就不一定在满足\(a_i\)的限制,但是左右两个区间依旧满足(因为我们是分别排序)
直接用权值树状数组计算右边对与左边的贡献
但是,如果要求小于等于,就要考虑有两个值其\(a_I,b_i,c_i\)均相同的情况
这样的话我们就去重
将重复\(n\)个的元素的权值改为\(n\)
最后
\(cnt_{ai.ans + ai.val-1}+=ai.ans\)
即可
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cctype>
#include<queue>
#include<stack>
using namespace std;
const int N = 1e5 + 3;
const int M = 2e5 + 3;
int n,k;
struct BIT{
int c[M];
inline int lowbit(int x){return x & -x;}
inline void ins(int x,int v){
for(;x <= k;x += lowbit(x)) c[x] += v;
}
inline int query(int x){
int res = 0;
for(;x;x -= lowbit(x)) res += c[x];
return res;
}
}T;
struct node{
int x,y,z;
int val,ans;
}a[N],b[N];
int cnt[N];
inline int read(){
char ch = getchar();int v = 0,c = 1;
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
inline bool cmpx(node xx,node yy){
if(xx.x != yy.x)
return xx.x < yy.x;
if(xx.y != yy.y)
return xx.y < yy.y;
return xx.z < yy.z;
}
inline bool cmpy(node xx,node yy){
if(xx.y != yy.y)
return xx.y < yy.y;
return xx.z < yy.z;
}
inline void solve(int l,int r){
if(l == r) return ;
int mid = (l + r) >> 1;
solve(l,mid);solve(mid + 1,r);
// printf("l:%d r:%d\n",l,r);
sort(a + l,a + mid + 1,cmpy);
sort(a + mid + 1,a + r + 1,cmpy);
// for(int i = l;i <= r;++i) printf("%d %d\n",a[i].y,a[i].z);
int top = l;
for(int i = mid + 1;i <= r;++i){
for(;top <= mid && a[top].y <= a[i].y;top++)
T.ins(a[top].z,a[top].val);
// printf("%d %d %d\n",top,i,T.query(a[i].z));
a[i].ans += T.query(a[i].z);
}
for(int i = l;i < top;++i) T.ins(a[i].z,-a[i].val);
}
int main(){
n = read(),k = read();
for(int i = 1;i <= n;++i)
b[i].x = read(),b[i].y = read(),b[i].z = read();
sort(b + 1,b + n + 1,cmpx);
int c = 0,num = 0;
for(int i = 1;i <= n;++i){
c++;
if(b[i].x != b[i + 1].x || b[i].y != b[i + 1].y || b[i].z != b[i + 1].z)
a[++num] = b[i],a[num].val = c,c = 0;
}
swap(num,n);//for(int i = 1;i <= n;++i) printf("%d %d %d %d\n",a[i].x,a[i].y,a[i].z,a[i].val);
solve(1,n);
// for(int i = 1;i <= n;++i) printf("%d ",a[i].ans);puts("");
for(int i = 1;i <= n;++i) cnt[a[i].ans + a[i].val - 1] += a[i].val;
for(int i = 0;i < num;++i) printf("%d\n",cnt[i]);
return 0;
}
CF669E. Little Artem and Time Machine
CDQ的板子题了
我们以输入的操作顺序为第一维
操作的时间为第二维
第三维就直接查询有多少数等于他就好了
但是由于排序是将
sort(a + l,a + mid + 1,cmp)
写成了
sort(a + l + 1,a + mid + 1,cmp)
然后,调了一下午,还去找\(wqy\)学长丢人
#include<cstdio>
#include<cstring>
#include<cctype>
#include<map>
#include<algorithm>
#include<iostream>
#define LL long long
using namespace std;
const int N = 1e5 + 3;
int n;
struct Q{
int type;
LL time;
LL val;
int id;
int ans;
}a[N];
map <LL,int> m;
inline LL read(){
char ch = getchar();long long v = 0,c = 1;
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
inline bool cmp(Q x,Q y){
return x.time < y.time;
}
inline bool cmp2(Q x,Q y){
return x.id < y.id;
}
inline void solve(int l,int r){
if(l == r) return ;
int mid = (l + r) >> 1;
solve(l,mid);solve(mid + 1,r);
// printf("l:%d r:%d\n",l,r);
sort(a + l,a + mid + 1,cmp);
sort(a + mid + 1,a + r + 1,cmp);
// for(int i = l;i <= mid;++i) printf("%d %lld %lld\n",a[i].type,a[i].time,a[i].val);
// printf("---------------\n");
// for(int i = mid + 1;i <= r;++i) printf("%d %lld %lld\n",a[i].type,a[i].time,a[i].val);
int top = l;
for(int i = mid + 1;i <= r;++i){
while(i <= r && a[i].type != 3) ++i;
if(i > r) break;
while(top <= mid && a[top].time <= a[i].time){
if(a[top].type == 1) m[a[top].val]++;
else if(a[top].type == 2) m[a[top].val]--;
top++;
}
a[i].ans += m[a[i].val];
}
m.clear();
}
int main(){
n = read();
for(int i = 1;i <= n;++i){
a[i].type = read();
a[i].time = read();
a[i].val = read();
a[i].id = i;
}
solve(1,n);
sort(a + 1,a + n + 1,cmp2);
for(int i = 1;i <= n;++i) if(a[i].type == 3) printf("%d\n",a[i].ans);
return 0;