cdq分治

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cdq分治相关的知识,希望对你有一定的参考价值。

啊最近头好晕还要学这么多东西更晕了

心理状态也没什么转好的迹象阿 似乎是越来越喜欢放大负能量了

而且完全不想做总结 也完全写不动题qwq

大概是要废了= =


 

啊那么cdq分治呢大概就是利用了离线的力量

写过归并的某些题的应该能明白 大概就是你分治回来之后,中间有一部分是要再次处理的

于是cdq分治就这么将查询与修改的关系提前确定了

昨天下午才开始学我觉得大概就这样了吧 以后要有什么更深刻的理解了再回来补充qwq

现在真的整个人都发虚

 

1.三维偏序裸题 陌上花开

一维sort二维归并三维树状数组

入门题 基本是靠着打这份代码才明白了思想

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<string>
 7 #define ll long long
 8 #define db double
 9 #define N 120000
10 #define inf
11 using namespace std;
12 struct hh{
13     int s,c,m;
14 }a[N];
15 int q[N],tree[N*4],s[N],ss[N],p[N],num[N],la[N],ans[N];
16 int n,k,cnt=0;
17 bool cmp(hh x,hh y){
18     if (x.s==y.s&&x.c==y.c) return x.m<y.m;
19     if (x.s==y.s) return x.c<y.c;
20     return x.s<y.s;
21 }
22 int lowbit(int x){
23     return x&(-x);
24 }
25 void add(int x,int v){
26     while (x<=k){
27         tree[x]+=v;
28         x+=lowbit(x);
29     }
30 }
31 int query(int x){
32     int ans=0;
33     while (x>0){
34         ans+=tree[x];
35         x-=lowbit(x);
36     }
37     return ans;
38 }
39 void merge(int l,int r){
40     if (l==r){
41         s[l]=l;return ;
42     }
43     int mid=(l+r)>>1;
44     merge(l,mid);merge(mid+1,r);
45     int i=l,j=mid+1;
46     for (int k=l;k<=r;++k){
47         if (j<=r&&(i>mid||p[s[i]]>p[s[j]])) ans[s[j]]+=query(q[s[j]]),ss[k]=s[j++];
48         else add(q[s[i]],num[s[i]]),ss[k]=s[i++];    
49     }
50     for (int k=l;k<=mid;++k) add(q[k],-num[k]);
51     for (int k=l;k<=r;++k) s[k]=ss[k];
52 }
53 int main(){
54     freopen ("1.in","r",stdin);
55     freopen ("1.out","w",stdout);
56     scanf ("%d%d",&n,&k);
57     for (int i=1;i<=n;++i) scanf ("%d%d%d",&a[i].s,&a[i].c,&a[i].m);
58     sort(a+1,a+n+1,cmp);
59     for (int i=1;i<=n;++i){
60         if (a[i].s!=a[i-1].s||a[i].c!=a[i-1].c||a[i].m!=a[i-1].m) p[++cnt]=a[i].c,q[cnt]=a[i].m;
61         num[cnt]++;
62     }
63     merge(1,cnt);
64     for (int i=1;i<=cnt;++i) la[ans[i]+num[i]-1]+=num[i];
65     for (int i=0;i<n;++i) printf ("%d\n",la[i]);
66     return 0;
67   }

 

2.mokia

好想写成中文

(可能是膜可鸭)

主要是询问要拆分一下 写过平面前缀和的大概能理解 另外千万不要像我一样搞个什么pq这种长得很像的放一起 用错了好久qaq

另外 排序的时候不能只管你要排序的那一个量 其他的也要判断(惨痛脸)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<string>
 7 #define ll long long
 8 #define db double
 9 #define N 2000020 
10 #define inf
11 using namespace std;
12 int a,n,cnt=0,c=0;
13 int ans[N],tree[N<<1];
14 bool b[N];
15 struct hh{
16     int x,y,v,id,t,l;
17 }m[N],t[N];
18 bool cmp(hh a,hh b){
19     if (a.x==b.x&&a.y==b.y) return a.l<b.l;
20     if (a.x==b.x) return a.y<b.y;
21     return a.x<b.x;
22 }
23 int lowbit(int x){
24     return x&(-x);
25 }
26 void add(int x,int v){
27     while (x<=n){
28         tree[x]+=v;
29         x+=lowbit(x);
30     }
31 }
32 int query(int x){
33     int tmp=0;
34     while (x>0){
35         tmp+=tree[x];
36         x-=lowbit(x);
37     }
38     return tmp;
39 }
40 void merge(int l,int r){
41     if (l==r)  return ;
42     int mid=(l+r)>>1;
43     merge(l,mid);merge(mid+1,r);
44     for (int i=l;i<=r;++i) t[i]=m[i],t[i].l=(i<=mid?0:1);
45     sort(t+l,t+r+1,cmp);
46     for (int k=l;k<=r;++k){
47         if ((!t[k].l)&&t[k].v) add(t[k].y,t[k].v);
48         else if (t[k].l&&(!t[k].v)) ans[t[k].id]+=(t[k].t*query(t[k].y));
49     }
50     for (int k=l;k<=r;++k)
51         if ((!t[k].l)&&t[k].v) add(t[k].y,-t[k].v);
52 }
53 int main(){
54     freopen ("mokia.in","r",stdin);
55     freopen ("mokia.out","w",stdout);
56     scanf ("%d%d",&a,&n);
57     while (1){
58         scanf ("%d",&a);
59         if (a==3) break;
60         c++;
61         int o,p,q,r;
62         if (a==1){
63             scanf ("%d%d%d",&o,&p,&q);
64             m[++cnt]=hh{o,p,q,c};
65         }
66         if (a==2){
67             b[c]=1;
68             scanf ("%d%d%d%d",&o,&p,&q,&r);
69             m[++cnt]=hh{q,r,0,c,1};
70             m[++cnt]=hh{q,p-1,0,c,-1};
71             m[++cnt]=hh{o-1,r,0,c,-1};
72             m[++cnt]=hh{o-1,p-1,0,c,1};
73         }
74     }
75     merge(1,cnt);
76     for (int i=1;i<=c;++i) if (b[i]) printf ("%d\n",ans[i]);
77     return 0;
78   }

 

3.动态逆序对

想着第三题也应该算入门了多自己想想吧 结果naive

原本只想到了二维(可能头晕傻了 后来渐渐感觉不对了就去看题解了

突然一下醒过来发现我是个sb 然后继续头晕

http://blog.csdn.net/u011542204/article/details/50571409 这篇博客讲得超级nice

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<string>
 7 #define ll long long
 8 #define db double
 9 #define N 101000
10 #define inf
11 using namespace std;
12 int n,m,cnt=0;
13 int tr[N<<1],p[N];
14 ll ans[N],asn[N],la[N];
15 struct hh{
16     int x,y,t;
17 }s[N],t[N];
18 int lowbit(int x){
19     return x&(-x);
20 }
21 void add(int x,int v){
22     while (x<=n){
23         tr[x]+=v;
24         x+=lowbit(x);
25     }
26 }
27 int query(int x){
28     int ans=0;
29     while (x>0){
30         ans+=tr[x];
31         x-=lowbit(x);
32     }
33     return ans;
34 }
35 void work(int l,int r){
36     if (l>=r) return ;
37     int mid=(l+r)>>1;
38     int h1=l-1,h2=mid;
39     for (int i=l;i<=r;++i){
40         if (s[i].t<=mid) t[++h1]=s[i];
41         else t[++h2]=s[i];
42     }
43     h1=l;
44     for (int i=mid+1;i<=r;++i){
45         for (;h1<=mid&&t[h1].x<t[i].x;h1++) add(t[h1].y,1);
46         ans[t[i].t]+=(h1-l)-query(t[i].y);
47     }
48     for (int i=l;i<=h1-1;++i) add(t[i].y,-1);
49     h1=mid;
50     for (int i=r;i>=mid+1;--i){
51         for (;h1>=l&&t[h1].x>t[i].x;h1--) add(t[h1].y,1);
52         asn[t[i].t]+=query(t[i].y-1);
53     }
54     for (int i=mid;i>h1;--i) add(t[i].y,-1);
55     for (int i=l;i<=r;++i) s[i]=t[i];
56     work(l,mid);work(mid+1,r);
57 }
58 int main(){
59     freopen ("7.in","r",stdin);
60     freopen ("7.out","w",stdout);
61     scanf ("%d%d",&n,&m);
62     int x;
63     for (int i=1;i<=n;++i){
64         scanf ("%d",&s[i].y);
65         s[i].x=i;p[s[i].y]=i;
66     }
67     for (int i=1;i<=m;++i){
68         scanf ("%d",&x);
69         s[p[x]].t=n-i+1;
70     }
71     int c=0;
72     for (int i=1;i<=n;++i) if (!s[i].t) s[i].t=++c;
73     work(1,n);
74     for (int i=1;i<=n;++i) la[i]=la[i-1]+ans[i]+asn[i];
75     for (int i=n;i>=n-m+1;--i) printf("%lld\n",la[i]);
76     return 0;
77   }

然后今天好像就要过去了呀qwq

在太阳落山之前好歹再去学点什么吧= - =

以上是关于cdq分治的主要内容,如果未能解决你的问题,请参考以下文章

模板:CDQ分治

初窥CDQ分治

HDU 3507 Print Article(CDQ分治+分治DP)

bzoj 2683 简单题 cdq分治

bzoj4237: 稻草人 cdq分治 单调栈

cdq分治浅谈