nyoj 9 poj 2528 posters

来源:互联网 发布:59pic美女图片源码 编辑:程序博客网 时间:2024/05/21 11:25

线段树的离散化,因为贴海报的范围是1~1e7,肯定开不了那么大的数组,但是n的范围很小只有1e4,所以可以离散化处理,什么叫做离散化?
百度百科:离散化,把无限空间中无限的个体映射到有限的空间中去,以此提高算法的时空效率。
比如一组数据:
3
10000 100000
10000 20000
20000 100000
心算就能算出来应该是3,我们可以把10000假设成1,100000假设成10,20000假设成2,这样就成了
3
1 10
1 2
2 10
其实还可以继续缩小 因为10000最小排在第一,20000第二,100000第三,所以假设10000为1,20000为2,100000为3
即:
3
1 3
1 2
2 3
因此离散化就避免了很大的空间浪费,所以虽然说数的范围是1~1e7,但是只有2e4个数,我们通过映射,可以将这些数映射成1~20000的范围,这样就只需要开2w的数组即可,而不再需要开1e7的数组,是不是很神奇啊?哈哈~
不过应该怎么映射?
可以通过map映射,不过可能会超时,我们可以将所有的数sort一下,再去重,然后每个数都对应了一个次序,按照这个次序来建树,更新,最后再求范围就可以了,
poj:

http://poj.org/problem?id=2528

poj AC代码(nyoj wa):

#include<stdio.h>#include<string.h>#include<algorithm>#include<iostream>using namespace std;int num[20010],k,c[20010];struct node{    int left,right,value,mid;} w[80020];struct stu{    int x,y;} a[10010];void build(int l,int r,int tr){    w[tr].value=-1;    w[tr].left=l,w[tr].right=r;    if(l==r)  return ;    int mid=(l+r)/2;    w[tr].mid=mid;    build(l,mid,tr*2);    build(mid+1,r,tr*2+1);}int Search(int x){    int l=1,r=k,j;    while(l<=r)    {        j=(l+r)/2;        if(num[j]==x)            return j;        if(x<num[j])            r=j-1;        else            l=j+1;    }}void update(int l,int r,int zhi,int tr){    if(l==w[tr].left&&r==w[tr].right)    {        w[tr].value=zhi;            return ;    }    if(w[tr].value!=-1)     w[tr*2].value=w[tr*2+1].value=w[tr].value,w[tr].value=-1;    if(r<=w[tr].mid)        update(l,r,zhi,tr*2);    else if(l>w[tr].mid)        update(l,r,zhi,tr*2+1);    else        update(l,w[tr].mid,zhi,tr*2),update(w[tr].mid+1,r,zhi,tr*2+1);}void searchtree(int tr){    if(w[tr].value!=-1)        {c[w[tr].value]++;return;}    if(w[tr].left==w[tr].right)  {return;}    searchtree(tr*2),searchtree(tr*2+1);}int main(){    int nn;    scanf("%d",&nn);    while(nn--)    {        memset(c,0,sizeof(c));        int n,i;        k=0;        scanf("%d",&n);        for(i=1; i<=n; i++)            scanf("%d%d",&a[i].x,&a[i].y),num[++k]=a[i].x,num[++k]=a[i].y;        sort(num+1,num+k+1);        k=unique(num+1,num+k+1)-num-1;        build(1,k,1);        for(i=1; i<=n; i++)        {            int x=Search(a[i].x);            int y=Search(a[i].y);            update(x,y,i,1);        }        searchtree(1);        int s=0;        for(i=1; i<=n; i++)            if(c[i])                s++;        printf("%d\n",s);    }}

然后换个oj提交

http://acm.nyist.net/JudgeOnline/problemset.php

这是会惊奇的发现wa了,为什么?
再来测一组数据
3
1 10
1 4
6 10
实际结果应该为3,但是代码的结果为2,为什么?
因为映射过程中成了:
3
1 4
1 2
3 4
不难理解为什么代码结果和实际为什么不一样,但是poj后台数据水,就a了,,幸亏我nyoj后台叼~,哈哈,,
改进代码:

#include<stdio.h>#include<string.h>#include<algorithm>#include<set>   //set用来记录海报个数#include<iostream>using namespace std;set<int>s;   //set容器int num[20010],k;struct node{    int left,right,value,mid;} w[40020];struct stu{    int x,y;} a[10010];void build(int l,int r,int tr)   //建树,但是不是一般的建树法{    w[tr].value=-1;    w[tr].left=l,w[tr].right=r;    int mid=(l+r)/2;    w[tr].mid=mid;    if(l+1<r)   //注意此处的建树法    {        build(l,mid,tr*2);        build(mid,r,tr*2+1);    }}int Search(int x)  //二分查找用来查找这个数对应的是离散化的哪个数字,{    int l=1,r=k,j;    while(l<=r)    {        j=(l+r)/2;        if(num[j]==x)            return j;        if(x<num[j])            r=j-1;        else            l=j+1;    }}void update(int l,int r,int zhi,int tr)  //区间更新{    if(l==w[tr].left&&r==w[tr].right)    //若查找到此区间,则“贴上海报”    {        w[tr].value=zhi;        return ;    }    if(w[tr].value!=-1)  //若此区间没有找到,且此处有海报,就将其分成小块,        w[tr*2].value=w[tr*2+1].value=w[tr].value,w[tr].value=-1;    if(r<=w[tr].mid)        update(l,r,zhi,tr*2);    else if(l>=w[tr].mid)        update(l,r,zhi,tr*2+1);    else        update(l,w[tr*2].right,zhi,tr*2),update(w[tr*2+1].left,r,zhi,tr*2+1);}void searchtree(int tr)  //查询{    if(w[tr].value!=-1)      s.insert(w[tr].value);   //找到海报就放进set容器中,同时这个区间的子区间就不再统计,    else if(w[tr].right>w[tr].left+1)     {        searchtree(2*tr);        searchtree(2*tr+1);    }}int main(){    int nn;    scanf("%d",&nn);    while(nn--)    {        int n,i;        k=0;        scanf("%d",&n);        for(i=1; i<=n; i++)            scanf("%d%d",&a[i].x,&a[i].y),a[i].x--,num[++k]=a[i].x,num[++k]=a[i].y;  //num数组用来排序,便于离散化,至于为什么要a[i]--,自己想想,哈哈~        sort(num+1,num+k+1);   //num排序,        k=unique(num+1,num+k+1)-num-1;  //用了unique函数,目的是去除排序后的重复数字,        build(1,k,1);  //建树        for(i=1; i<=n; i++)  //n次更新        {            int x=Search(a[i].x);            int y=Search(a[i].y);            update(x,y,i,1);        }        searchtree(1);  //查询有多少个海报        printf("%d\n",s.size());  //输出海报个数        s.clear();  //清空set容器    }    return 0;}
0 0
原创粉丝点击