2019 南昌网络赛icpc I题 cdq分治或分块

题意:给你一个数组,然后每次有两种操作,操作一是修改数组里的数,操作二是查询区间[ l , r ] 里有多少个子区间满足以下条件:1、子区间内的数全部相同。2、子区间内的数在x到y之间。3、子区间得是不能延伸的。

题目链接:https://nanti.jisuanke.com/t/41356

题解:首先转化问题,设 b[ i ] = a[i]==a[i-1] ? 0 : a[i],然后问题就变成了问询区间内有多少个x到y之间的数。(注意左端点特判)这不就是主席树。。。。带修改。。。好,树状数组加主席树。。。然后题解来一句,卡树套树。正解cdq。虽然分块+树状数组可以过,但是cdq常数真的十分优秀。所以这题用了cdq和分块两种解法来写。

cdq:867ms(用c++11居然791ms??),分块:3027ms

首先分块:分成若干个块,每一个块就是一个树状数组,修改操作直接在该块树状数组修改。查询的话,直接每一个块的树状数组查询,思路很好想,实现也好写。

代码如下:

  1 /*************************************************************************
  2     > File Name: nanchangI.cpp
  3 # File Name: nanchangI.cpp
  4 # Author : xiaobuxie
  5 # QQ : 760427180
  6 # Email:760427180@qq.com
  7 # Created Time: 2019年09月09日 星期一 22时10分02秒
  8  ************************************************************************/
  9 
 10 #include<iostream>
 11 #include<cstdio>
 12 #include<map>
 13 #include<cmath>
 14 #include<cstring>
 15 #include<set>
 16 #include<queue>
 17 #include<vector>
 18 #include<algorithm>
 19 using namespace std;
 20 typedef long long ll;
 21 #define inf 0x3f3f3f3f
 22 #define pq priority_queue<int,vector<int>,greater<int> >
 23 ll gcd(ll a,ll b){
 24     if(a<b) return gcd(b,a);
 25     return b==0?a:gcd(b,a%b);
 26 }
 27 
 28 const int N=2e5+9;
 29 const int M=sqrt(N/(log(N)))+9;
 30 int a[N],b[N],id[N];
 31 int tr[M][N];
 32 int n,m;
 33 void add(int p,int x,int v){ for(;x<=n;x+=x&(-x)) tr[p][x]+=v;}
 34 int sum(int p,int x){
 35     int res=0;
 36     for(;x;x-=x&(-x)) res+=tr[p][x];
 37     return res;
 38 }
 39 int main(){
 40     scanf("%d %d",&n,&m);
 41     //int block=sqrt(n*log(n)/log(2));
 42     int block=sqrt(n*log(n+1));
 43     for(int i=1;i<=n;++i) scanf("%d",a+i);
 44     b[1]=a[1];
 45     for(int i=2;i<=n;++i) b[i]= a[i]==a[i-1] ? 0 : a[i];
 46     int cnt=1;
 47     for(int i=1;i<=n;){
 48         for(int j=0;j<block && i+j<=n;++j) id[i+j]=cnt;
 49         ++cnt; i+=block;
 50     }
 51     for(int i=1;i<=n;++i) if(b[i]) add(id[i],b[i],1);
 52     for(int i=1;i<=m;++i){
 53         int opt; scanf("%d",&opt);
 54         if(opt==1){
 55             int p,v;scanf("%d %d",&p,&v);
 56             if(b[p]) add(id[p],b[p],-1);
 57             if(p==1){
 58                 add(id[p],v,1);
 59                 b[p]=a[p]=v;
 60             }
 61             else if(v!=a[p-1]) add(id[p],v,1),b[p]=a[p]=v;
 62             else b[p]=0,a[p]=v;
 63 
 64             if(p!=n){
 65                 add(id[p+1],b[p+1],-1);
 66                 if(a[p]!=a[p+1]) add(id[p+1],a[p+1],1),b[p+1]=a[p+1];
 67                 else b[p+1]=0;
 68             }
 69 
 70         }
 71         else{
 72             int l,r,x,y; scanf("%d %d %d %d",&l,&r,&x,&y);
 73             if(l==r){
 74                 if(a[l]>=x && a[l]<=y) puts("1");
 75                 else puts("0");
 76                 continue;
 77             }
 78             ++l;
 79             int ans=0;
 80             int le=l,ri=r;
 81             //cerr<<id[le]<<' '<<id[ri]<<endl;
 82             if(id[le]==id[ri] || id[le]==id[ri]-1){
 83                 for(int i=le;i<=ri;++i){
 84                     //cerr<<i<<' '<<b[i]<<endl;
 85                     if(b[i]>=x && b[i]<=y) ++ans;
 86                 }
 87             }
 88 
 89             else{
 90                 for(;id[le]==id[l];++le) if(b[le]>=x && b[le]<=y) ++ans;
 91                 for(;id[ri]==id[r];--ri) if(b[ri]>=x && b[ri]<=y) ++ans;
 92                 for(int i=id[le];i<=id[ri];++i) ans+=sum(i,y)-sum(i,x-1);
 93             }
 94             //cerr<<ans<<endl;
 95             if(a[l-1]>=x && a[l-1]<=y) ++ans;
 96             printf("%d\n",ans);
 97         }
 98     }
 99     return 0;
100 }
View Code

 

然后说说正解cdq吧:首先我们可以把询问拆成两个操作,对[ 1, l-1 ]和 [ 1, r ] 询问x到y之间有多少数。然后每个操作有三个属性:id(哪一位),时间,ty(类型),所以就隐隐约约看到三维偏序问题。可以这样看,每次询问操作,就是看id比他小的,并且时间比他小的x到y的数多少个。一开始读入就是按照时间来读入的(第一维)。然后对id进行分治(第二维),然后注意cdq中经常注意的一点:左区间的修改影响右区间的查询,也就是说左指针操作是修改才进行,右指针操作是询问才进行。每个询问操作要看他时间轴左边的,在同一个子区间的会分治时处理,不在同一个子区间的归并会处理,所以不重不漏。

最后记得清空树状数组。

然后好像说对结构体进行多次移动会变慢,所以这里写成了分开的了。开起来可能不大习惯。

  1 /*************************************************************************
  2     > File Name: nanchangeI.cpp
  3 # File Name: nanchangeI.cpp
  4 # Author : xiaobuxie
  5 # QQ : 760427180
  6 # Email:760427180@qq.com
  7 # Created Time: 2019年09月10日 星期二 20时05分47秒
  8  ************************************************************************/
  9 
 10 #include<iostream>
 11 #include<cstdio>
 12 #include<map>
 13 #include<cmath>
 14 #include<cstring>
 15 #include<set>
 16 #include<queue>
 17 #include<vector>
 18 #include<algorithm>
 19 using namespace std;
 20 typedef long long ll;
 21 #define inf 0x3f3f3f3f
 22 #define pq priority_queue<int,vector<int>,greater<int> >
 23 ll gcd(ll a,ll b){
 24     if(a<b) return gcd(b,a);
 25     return b==0?a:gcd(b,a%b);
 26 }
 27 
 28 const int M=2e6+9;
 29 const int N=2e5+8;
 30 int id[M],ty[M],X[M],Y[M],ansid[M],val[M];
 31 int ans[N];
 32 int B[M],A[M],tr[N];
 33 int a[N],b[N];
 34 int n,m;
 35 void add(int x,int v){
 36     for(;x<=n;x+=x&(-x)) tr[x]+=v;
 37 }
 38 int query(int x){
 39     int res=0;
 40     for(;x;x-=x&(-x)) res+=tr[x];
 41     return res;
 42 }
 43 void cdq(int l,int r){
 44     if(l==r) return;
 45     int m=(l+r)>>1;
 46     cdq(l,m); cdq(m+1,r);
 47     for(int i=l,t1=l,t2=m+1;i<=r;++i){
 48         if(t1<=m && (id[ A[t1] ] <= id[ A[t2] ] || t2>r)){
 49             B[i]=A[t1];
 50             if(ty[ A[t1] ]==1){
 51                 if(val[ A[t1] ]>=0) add(val[ A[t1] ],1);
 52                 else add(-val[ A[t1] ],-1);
 53             }
 54             ++t1;
 55         }
 56         else{
 57             B[i]=A[t2];
 58             if(ty[ A[t2] ]==2){
 59                 ans[ ansid[A[t2]] ]+=query(X[ A[t2] ]);
 60                 ans[ ansid[A[t2]] ]-=query(Y[ A[t2] ]);
 61             }
 62             if(ty[ A[t2] ]==3){
 63                 ans[ ansid[A[t2]] ]-=query(X[ A[t2] ]);
 64                 ans[ ansid[A[t2]] ]+=query(Y[ A[t2] ]);
 65             }
 66             ++t2;
 67         }
 68     }
 69     for(int i=l;i<=m;++i){
 70         if(ty[ A[i] ]==1){
 71             if(val[ A[i] ]>=0) add(val[ A[i] ],-1);
 72             else add(-val[ A[i] ],1);
 73         }
 74     }
 75     for(int i=l;i<=r;++i) A[i]=B[i];
 76 }
 77 int main(){
 78     scanf("%d %d",&n,&m);
 79     int tot=0;
 80     for(int i=1;i<=n;++i) scanf("%d",a+i);
 81     b[1]=a[1];
 82     for(int i=2;i<=n;++i) b[i] = a[i]==a[i-1] ? 0 : a[i];
 83     for(int i=1;i<=n;++i){
 84         if(!b[i]) continue;
 85         id[++tot]=i; ty[tot]=1; val[tot]=b[i];
 86     }
 87     int cnt=0;
 88     for(int i=1;i<=m;++i){
 89         int opt; scanf("%d",&opt);
 90         if(opt==1){
 91             int p,v; scanf("%d %d",&p,&v);
 92             if(b[p]) id[++tot]=p; val[tot]=-b[p]; ty[tot]=1;
 93             if(p==1){
 94                 id[++tot]=p; val[tot]=v;     ty[tot]=1;
 95                 b[p]=a[p]=v;
 96             }
 97             else{
 98                 if(v!=a[p-1]){
 99                     id[++tot]=p; val[tot]=v;     ty[tot]=1;
100                     a[p]=b[p]=v;
101                 }
102                 else a[p]=v,b[p]=0;
103             }
104 
105             if(p!=n){
106                 if(b[p+1]) id[++tot]=p+1; val[tot]=-b[p+1]; ty[tot]=1;
107                 if(a[p]!=a[p+1]){
108                     b[p+1]=a[p+1];
109                     id[++tot]=p+1; val[tot]=b[p+1]; ty[tot]=1;
110                 }
111                 else b[p+1]=0;
112             }
113         }
114         else{
115             int l,r,x,y; scanf("%d %d %d %d",&l,&r,&x,&y);
116             if(l==r){
117                 if(a[l]>=x && a[l]<=y) ans[++cnt]=1;
118                 else ans[++cnt]=0;
119                 continue;
120             }
121             ++l; ++cnt;
122             ty[++tot]=2; id[tot]=l-1; X[tot]=x-1; Y[tot]=y; ansid[tot]=cnt;
123             ty[++tot]=3; id[tot]=r;   X[tot]=x-1; Y[tot]=y; ansid[tot]=cnt;
124             if(a[l-1]>=x && a[l-1]<=y) ans[cnt]++;
125         }
126     }
127     for(int i=1;i<=tot;++i) A[i]=i;
128     cdq(1,tot);
129     for(int i=1;i<=cnt;++i) printf("%d\n",ans[i]);
130     return 0;
131 }
View Code

 

用结构体试了一下,居然跑了765ms。。。。那以后就用结构体打好了,又清晰,又不慢。。。

  1 /*************************************************************************
  2     > File Name: nanchangeI.cpp
  3 # File Name: nanchangeI.cpp
  4 # Author : xiaobuxie
  5 # QQ : 760427180
  6 # Email:760427180@qq.com
  7 # Created Time: 2019年09月10日 星期二 20时05分47秒
  8  ************************************************************************/
  9 
 10 #include<iostream>
 11 #include<cstdio>
 12 #include<map>
 13 #include<cmath>
 14 #include<cstring>
 15 #include<set>
 16 #include<queue>
 17 #include<vector>
 18 #include<algorithm>
 19 using namespace std;
 20 typedef long long ll;
 21 #define inf 0x3f3f3f3f
 22 #define pq priority_queue<int,vector<int>,greater<int> >
 23 ll gcd(ll a,ll b){
 24     if(a<b) return gcd(b,a);
 25     return b==0?a:gcd(b,a%b);
 26 }
 27 
 28 const int M=2e6+9;
 29 const int N=2e5+8;
 30 struct node{
 31     int id,ty,x,y,ansid,val,ord;
 32 }A[M],B[M];
 33 int tr[N];
 34 int a[N],b[N],ans[N];
 35 int n,m;
 36 void add(int x,int v){
 37     for(;x<=n;x+=x&(-x)) tr[x]+=v;
 38 }
 39 int query(int x){
 40     int res=0;
 41     for(;x;x-=x&(-x)) res+=tr[x];
 42     return res;
 43 }
 44 void cdq(int l,int r){
 45     if(l==r) return;
 46     int m=(l+r)>>1;
 47     cdq(l,m); cdq(m+1,r);
 48     for(int i=l,t1=l,t2=m+1;i<=r;++i){
 49         if(t1<=m && (A[t1].id <= A[t2].id || t2>r)){
 50             if(A[t1].ty==1){
 51                 if( A[t1].val >=0) add( A[t1].val,1);
 52                 else add(-A[t1].val,-1);
 53             }
 54             B[i]=A[t1];
 55             ++t1;
 56         }
 57         else{
 58             if( A[t2].ty==2){
 59                 ans[ A[t2].ansid ]+=query(A[t2].x);
 60                 ans[ A[t2].ansid ]-=query(A[t2].y );
 61             }
 62             if(A[t2].ty==3){
 63                 ans[ A[t2].ansid ]-=query( A[t2].x );
 64                 ans[ A[t2].ansid ]+=query( A[t2].y );
 65             }
 66             B[i]=A[t2];
 67             ++t2;
 68         }
 69     }
 70     for(int i=l;i<=m;++i){
 71         if( A[i].ty ==1){
 72             if( A[i].val >=0) add( A[i].val ,-1);
 73             else add(-A[i].val,1);
 74         }
 75     }
 76     for(int i=l;i<=r;++i) A[i]=B[i];
 77 }
 78 int main(){
 79     scanf("%d %d",&n,&m);
 80     int tot=0;
 81     for(int i=1;i<=n;++i) scanf("%d",a+i);
 82     b[1]=a[1];
 83     for(int i=2;i<=n;++i) b[i] = a[i]==a[i-1] ? 0 : a[i];
 84     for(int i=1;i<=n;++i){
 85         if(!b[i]) continue;
 86         A[++tot].id=i; A[tot].ty=1; A[tot].val=b[i];
 87     }
 88     int cnt=0;
 89     for(int i=1;i<=m;++i){
 90         int opt; scanf("%d",&opt);
 91         if(opt==1){
 92             int p,v; scanf("%d %d",&p,&v);
 93             if(b[p]) A[++tot].id=p; A[tot].val=-b[p]; A[tot].ty=1;
 94             if(p==1){
 95                 A[++tot].id=p; A[tot].val=v; A[tot].ty=1;
 96                 b[p]=a[p]=v;
 97             }
 98             else{
 99                 if(v!=a[p-1]){
100                     A[++tot].id=p; A[tot].val=v; A[tot].ty=1;
101                     a[p]=b[p]=v;
102                 }
103                 else a[p]=v,b[p]=0;
104             }
105 
106             if(p!=n){
107                 if(b[p+1]) A[++tot].id=p+1; A[tot].val=-b[p+1]; A[tot].ty=1;
108                 if(a[p]!=a[p+1]){
109                     b[p+1]=a[p+1];
110                     A[++tot].id=p+1; A[tot].val=b[p+1]; A[tot].ty=1;
111                 }
112                 else b[p+1]=0;
113             }
114         }
115         else{
116             int l,r,x,y; scanf("%d %d %d %d",&l,&r,&x,&y);
117             if(l==r){
118                 if(a[l]>=x && a[l]<=y) ans[++cnt]=1;
119                 else ans[++cnt]=0;
120                 continue;
121             }
122             ++l; ++cnt;
123             A[++tot].ty=2; A[tot].id=l-1; A[tot].x=x-1; A[tot].y=y; A[tot].ansid=cnt;
124             A[++tot].ty=3; A[tot].id=r;   A[tot].x=x-1; A[tot].y=y; A[tot].ansid=cnt;
125             if(a[l-1]>=x && a[l-1]<=y) ans[cnt]++;
126         }
127     }
128     for(int i=1;i<=tot;++i) A[i].ord=i;
129     cdq(1,tot);
130     for(int i=1;i<=cnt;++i) printf("%d\n",ans[i]);
131     return 0;
132 }
View Code

 

posted @ 2019-09-10 22:27  小布鞋  阅读(370)  评论(0编辑  收藏  举报