2012ACM ICPC杭州赛区网络赛
比赛的时候线段树死搞,害得我五个小时毫无收获,下来后发誓要做出来。搜了下,线段树貌似可以ac,单大多数说划分树,然后直接百度,看了一下,有些收获,分享一下自己的感受和大家分享一下吧。
划分树:
谈谈我对划分树的理解:实际上划分树是以线段树的形式模拟和记录快速排序的过程;
如何模拟:(回想快速排序:A数组分成两部分B,C,小于等于某个数x的放x的左边数组B,其余的放右边数组C,然后对B跟C做相同的操作),只不过划分树划分到左右两部分的时候要保证B数组的所有数与A数组中数的前后顺序一样,C数组也一样。
例如A(0 5 6 2 8)按x=5划分成B(0 2 5),C(6 8),B C数组中数的顺序固定,不能随意,后面会说明为什么要这样。
如何记录:(回想线段树:1->n 的下一层1->(1+n)/2和(1+n)/2+1->n,刚好和上面划分规则差不多)可以想象对于n的数组最多log[n]层
所用到的数据结构就一个结构体node{
array[Max] ;//记录这一层排成啥样了
num[Max];//num[i]记录前i个数有多少个进了左边数组
}
有了这些后那么求区间【a,b】中小于等于c的数的个数了===【1,b】-【1,a-1】中c的个数;
求【1,b】中的个数,直接进入第一层,如果划分的数为x;
两种情况:(至于等于,就细节处理吧)
1,c比x小,那么直接进左边数组找; num【b】中记录了【1,b】进入左边数组的个数,而且是在左边数组中靠左排列的,这就是上面为什么要按顺序排列的原因了;
2,c比x大,那么进入左边的个数就出来了,进入右边的数也同样在右边数组靠左排列递归求出;
至此为止算法基本讲完了,比赛的拿到题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4417
我的代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define Max 100001
int array[Max],sorted[Max];
struct N
{
int array[Max];
int num[Max];
}node[101];
int n,m;
int cmp(const void *a,const void *b)
{
return *(int *)a-*(int *)b;
}
int build(int l,int r,int pre)
{
if(l==r)
return 0;
int i,mid=(l+r)/2,lnextl=l,rnextl=mid+1,minnum=0,temp;
memset(node[pre].num+l,0,sizeof(int)*(r-l+1));
for(i=l;i<=r;i++)
{
if(node[pre].array[i]<sorted[mid])
{
minnum++;
}
}
temp=mid-l+1-minnum;
for(i=l;i<=r;i++)
{
if(node[pre].array[i]<sorted[mid])
{
node[pre+1].array[lnextl++]=node[pre].array[i];
node[pre].num[i]++;
}
else if(node[pre].array[i]==sorted[mid]&&temp>0)
{
node[pre+1].array[lnextl++]=sorted[mid];
node[pre].num[i]++;
temp--;
}
}
for(i=l;i<=r;i++)
{
if(node[pre].array[i]>=sorted[mid])
{
if(!node[pre].num[i])
{
node[pre+1].array[rnextl++]=node[pre].array[i];
}
}
}
for(i=l+1;i<=r;i++)
node[pre].num[i]+=node[pre].num[i-1];
build(l,mid,pre+1);
build(mid+1,r,pre+1);
return 0;
}
int serch(int l,int r,int w,int pre,int prel,int prer)
{
if(r<l)
return 0;
if(prel==prer)
{
return node[pre].array[prel]<=w;
}
int mid=(prel+prer)/2;
if(w>=sorted[mid])
{
return node[pre].num[r]+serch(mid+1,mid+(r-l+1)-node[pre].num[r],w,pre+1,mid+1,prer);
}
else
{
return serch(l,l+node[pre].num[r]-1,w,pre+1,prel,mid);
}
return 0;
}
int main()
{
int i,cases,a,b,c,ca=0;
scanf("%d",&cases);
while(cases--)
{
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
scanf("%d",&array[i]);
}
memcpy(sorted+1,array+1,sizeof(int)*n);
memcpy(node[1].array+1,array+1,sizeof(int)*n);
qsort(sorted+1,n,sizeof(int),cmp);
build(1,n,1);
printf("Case %d:\n",++ca);
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
printf("%d\n",serch(1,b+1,c,1,1,n)-serch(1,a,c,1,1,n));
}
}
return 0;
}
欢迎大家做评论,各种意见砸过来!