洛谷P3810 陌上花开 CDQ分治(三维偏序)
好,这是一道三维偏序的模板题
当然没那么简单.....
首先谴责洛谷一下:可怜的陌上花开的题面被无情的消灭了:
这么好听的名字#(滑稽)
那么我们看了题面后就发现:这就是一个三维偏序。只不过ans不加在一起,而是加在每朵花内部。
很裸的一道CDQ分治,CDQ一维,sort一维,TreeArray一维,然后就爆0了......
把cmp函数改完备之后还是爆0,为什么呢?
看一下这一组样例:
5 3
1 3 3
3 3 3
3 3 3
3 3 3
3 3 3
看得出来正确答案是1 0 0 0 4
但是我们的程序无情的输出了1 1 1 1 1
这表明了什么?要去重!
就用类似离散化的方式去重,然后就——爆0了!
......
然后发现是代码里一个小细节写错了,害得我调了一晚上...
上代码。
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 const int N = 100010,K = 200010; 5 struct Node 6 { 7 int a,b,c,ans,sum; 8 bool operator==(const Node &x)const 9 { 10 return (this->a==x.a)&&(this->b==x.b)&&(this->c==x.c); 11 } 12 }node[N]; 13 bool cmp_a(Node x,Node y) /// !!!! 14 { 15 if(x.a!=y.a)return x.a<y.a; 16 if(x.b!=y.b)return x.b<y.b; 17 return x.c<y.c; 18 } 19 bool cmp_b(Node x,Node y) 20 { 21 if(x.b!=y.b)return x.b<y.b; 22 return x.c<y.c; 23 } 24 int lowbit(int x){return x&(-x);} 25 int TA[K],n,k; 26 void add(int x,int a) 27 { 28 if(!x) return; 29 for(int i=x;i<=k;i+=lowbit(i)) TA[i]+=a; 30 return; 31 } 32 int getsum(int x) 33 { 34 if(!x)return 0;int ans=0; 35 for(int i=x;i>0;i-=lowbit(i)) ans+=TA[i]; 36 return ans; 37 } 38 void merge(int l,int r) 39 { 40 //printf("merge:%d %d\n",l,r); 41 int mid=(l+r)>>1; 42 sort(node+l,node+mid+1,cmp_b); 43 sort(node+mid+1,node+r+1,cmp_b); 44 int i=l,j=mid; 45 while(j<r) 46 { 47 j++; 48 while(node[i].b<=node[j].b&&i<=mid) 49 add(node[i].c,node[i].sum),i++; 50 node[j].ans+=getsum(node[j].c);//printf("node[%d].ans+=%d\n",j,getsum(node[j].c)); 51 } 52 for(j=l;j<i;j++) add(node[j].c,-1*node[j].sum);/// !!!! 53 //fill(TA,TA+K,0); 54 return; 55 } 56 void CDQ(int l,int r) 57 { 58 if(l==r) return; 59 int mid=(l+r)>>1; 60 CDQ(l,mid);CDQ(mid+1,r); 61 merge(l,r); 62 return; 63 } 64 int ans[N]; 65 int main() 66 { 67 scanf("%d%d",&n,&k); 68 for(int i=1;i<=n;i++) scanf("%d%d%d",&node[i].a,&node[i].b,&node[i].c); 69 sort(node+1,node+n+1,cmp_a); 70 int t=0,c=1; 71 for(int i=2;i<=n+1;i++)/// !!!!!!! 72 { 73 if(node[i]==node[i-1]) 74 { 75 c++; 76 } 77 else 78 { 79 node[++t]=node[i-1]; 80 node[t].sum=c; 81 c=1; 82 } 83 } 84 //for(int i=1;i<=t;i++) printf("%d %d %d %d\n",node[i].a,node[i].b,node[i].c,node[i].sum); 85 CDQ(1,t); 86 sort(node+1,node+1+t,cmp_a); 87 //for(int i=1;i<=t;i++) printf("%d ",node[i].ans);printf("\n"); 88 for(int i=1;i<=t;i++) ans[node[i].ans+node[i].sum-1]+=node[i].sum;///这里加上去掉的重复桦 89 for(int i=1;i<=n;i++) printf("%d\n",ans[i-1]); 90 return 0; 91 }
第一次写CDQ,繁琐的细节好多...