zoukankan      html  css  js  c++  java
  • HDU

    B - Color itHDU - 6183 

      题目大意:有三种操作,0是清空所有点,1是给点(x,y)涂上颜色c,2是查询满足1<=a<=x,y1<=b<=y2的(a,b)点一共有几种不同的颜色

      一开始做的时候直接就是开51个vector保存每个颜色相应的点,然后就是询问就是,暴力循环判断这个颜色存不存在一个满足条件的点,感觉最差情况下应该会超时,不过却过了

     1 #include<cstdio>
     2 #include<vector>
     3 using namespace std;
     4 struct Node{
     5     int x,y;
     6     Node(){}
     7     Node(int x,int y):x(x),y(y){}
     8 };
     9 vector<Node> c[58];
    10 int main()
    11 {
    12     int op,x,y,y1,cc;
    13     while(scanf("%d",&op)&&op!=3)
    14     {
    15         if(op==0)
    16         {
    17             for(int i=0;i<=50;i++)
    18                 c[i].clear();
    19         }
    20         else if(op==1)
    21         {
    22             scanf("%d%d%d",&x,&y,&cc);
    23             c[cc].push_back(Node(x,y)); 
    24         }
    25         else
    26         {
    27             scanf("%d%d%d",&x,&y,&y1);
    28             int ans=0;
    29             for(int i=0;i<=50;i++)
    30             {
    31                 for(int j=0;j<c[i].size();j++)
    32                     if(c[i][j].x<=x&&c[i][j].y>=y&&c[i][j].y<=y1)
    33                     {
    34                         ans++;
    35                         break;
    36                     }
    37             }
    38             printf("%d
    ",ans);
    39         }
    40     }
    41     return 0;
    42 }
    暴力过一切

      然后看网上有是线段树动态开点的做法,但实际上并不比上面暴力的写法快,反而慢上几十ms,不过可以当做一个算法扩展来联系。

      首先1操作肯定就是单点更新了,而2操作上已经限定了x的左边为1,所以我们以y轴来建线段树维护个区间内x的最小值,那么2操作就是区间查询了。但我们知道正常静态的线段树需要4*SIZE的节点空间来保存信息的,在这里又需要51颗线段树,也就是51*4*1000000的空间来保存节点信息,不知道你们电脑能不能开那么大的数组,反正我的电脑和OJ的虚拟机是不行的。但其实最多150000个1操作和2操作,并不需要那么大的空间。所以这时候需要用到线段树的动态开点了。

      静态的线段树,每个编号为x的节点,它的左孩子编号就为2*x,右孩子编号就为2*x+1,然后这个节点x,我们是保存它的区间L,R和其他一系列信息。而动态开点的话,对于编号为x的节点,它的左右孩子的编号就不一定是2*x和2*x+1的关系了,所以我们要保存下的是它的左右孩子的编号已经一系列相关的信息,然后对于每个节点就是当需要到它时再开辟它。其他操作就和静态的线段树差不多。

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 const int N=1001108;
     5 struct Tree{
     6     int lson,rson,minx;    
     7 }T[N];
     8 int tn,flag,root[52];
     9 //root就保存这个颜色对于的那棵线段树的根节点编号 
    10 void init()
    11 {
    12     tn=1;
    13     for(int i=0;i<=50;i++)
    14         root[i]=0;
    15 }
    16 void updata(int &id,int L,int R,int y,int x)//在这里用L,R来表示节点id的区间 
    17 {
    18     if(!id)
    19     {//需要到这个节点了,开辟这个节点 
    20         id=tn++;
    21         T[id].minx=N;
    22         T[id].lson=T[id].rson=0;//它的子节点还未用得上 
    23     }
    24     T[id].minx=min(T[id].minx,x);//更新最小的x值 
    25     //下面就是线段树的单点修改 
    26     if(L==R)
    27         return ;
    28     int mid=(L+R)>>1;
    29     if(y<=mid)
    30         updata(T[id].lson,L,mid,y,x); 
    31     else
    32         updata(T[id].rson,mid+1,R,y,x);
    33 }
    34 void query(int id,int L,int R,int l,int r,int x)
    35 {
    36     if(flag||!id)//如果已经有点满足条件,或者这个节点没开辟就返回 
    37         return ;
    38     if(l<=L&&r>=R)
    39     {
    40         if(T[id].minx<=x)
    41             flag=1;//在y1和y2范围内有个x满足条件 
    42         return ;
    43     }
    44     int mid=(L+R)>>1;
    45     if(l<=mid)
    46         query(T[id].lson,L,mid,l,r,x);
    47     if(r>mid)
    48         query(T[id].rson,mid+1,R,l,r,x);
    49 }
    50 int main()
    51 {
    52     int op,x,y,y2,c;
    53     init();
    54     while(~scanf("%d",&op)&&op!=3)
    55     {
    56         if(op==0)
    57             init();
    58         else if(op==1)
    59         {
    60             scanf("%d%d%d",&x,&y,&c);
    61             updata(root[c],1,1000000,y,x);
    62         }
    63         else
    64         {
    65             scanf("%d%d%d",&x,&y,&y2);
    66             int ans=0;
    67             for(int i=0;i<=50;i++)
    68             {
    69                 flag=0;
    70                 query(root[i],1,1000000,y,y2,x);
    71                 ans+=flag;
    72             }
    73             printf("%d
    ",ans);
    74         }
    75     }
    76     return 0; 
    77 }
    线段树下线段果

      正解是cdq分治,待我学成归来,再更新。。。我回来了

      cdq分治处理的话,就是三维偏序的一个处理,(操作时间,x轴,y轴),然后第一维已经有序,那么我们cdq分治处理第二维,然后线段树处理第三维。因为最多是50种颜色,那么我们采用状压的策略,把每个颜色C用2C来表示,然后线段树维护个区间或和。需要注意的就是y轴离散化下,不然容易超时。

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<vector>
      4 #define L(x) (x<<1)
      5 #define R(x) (x<<1|1)
      6 #define M(x) ((T[x].l+T[x].r)>>1)
      7 using namespace std;
      8 typedef long long ll;
      9 const int N=150118,Y=1000118;
     10 struct Tree{
     11     int l,r;
     12     ll val;
     13 }T[Y];
     14 struct Nop{
     15     int op,x,y,y1;
     16     ll val;//op1更新操作的val记录2^C,op2查询操作记录答案编号 
     17     friend bool operator <(const Nop &n1,const Nop &n2){
     18         return n1.x==n2.x ? n1.op<n2.op : n1.x<n2.x;
     19     }
     20 }P[N<<1],temp[N<<1];
     21 int pn=0,qn=0,newy[Y];
     22 bool num[Y]={0};
     23 vector<int> vy;
     24 ll ans[N]={0},cf2[52]={1};
     25 inline void addp(int op,int x,int y,int y1,ll val){
     26     P[pn++]=(Nop){op,x,y,y1,val};
     27 }
     28 inline void addy(int y)
     29 {
     30     if(!num[y])
     31     {
     32         num[y]=1;
     33         vy.push_back(y);
     34     }
     35 }
     36 void built(int id,int l,int r)
     37 {
     38     T[id].val=0;
     39     T[id].l=l,T[id].r=r;
     40     if(l==r)
     41         return ;
     42     built(L(id),l,M(id));
     43     built(R(id),M(id)+1,r);
     44 }
     45 //线段树单点修改 
     46 void updata(int id,int pos,ll val)
     47 {
     48     if(T[id].l==T[id].r&&T[id].l==pos)
     49     {
     50         if(val)
     51             T[id].val|=val;
     52         else
     53             T[id].val=0;
     54         return ;
     55     }
     56     if(pos<=M(id))
     57         updata(L(id),pos,val);
     58     else
     59         updata(R(id),pos,val);
     60     T[id].val=T[L(id)].val|T[R(id)].val;
     61 }
     62 //区间或和查询 
     63 ll query(int id,int l,int r)
     64 {
     65     ll ans=0;
     66     if(l<=T[id].l&&T[id].r<=r)
     67         return T[id].val;
     68     if(l<=M(id))
     69         ans|=query(L(id),l,r);
     70     if(r>M(id))
     71         ans|=query(R(id),l,r);
     72     return ans;
     73 }
     74 void cdq(int l,int r)
     75 {
     76     if(l==r)
     77         return ;
     78     int m=(l+r)>>1;
     79     cdq(l,m);
     80     cdq(m+1,r);
     81     int i=l,j=m+1,k=l;
     82     while(i<=m&&j<=r)
     83     {
     84         if(P[i]<P[j])
     85         {
     86             if(P[i].op==1)
     87                 updata(1,P[i].y,P[i].val);
     88             temp[k++]=P[i++];
     89         }
     90         else
     91         {
     92             if(P[j].op==2)
     93                 ans[P[j].val]|=query(1,P[j].y,P[j].y1);
     94             temp[k++]=P[j++];
     95         }
     96     }
     97     while(i<=m)
     98         temp[k++]=P[i++];
     99     while(j<=r)
    100     {
    101         if(P[j].op==2)
    102             ans[P[j].val]|=query(1,P[j].y,P[j].y1);
    103         temp[k++]=P[j++];
    104     }
    105     for(i=l;i<=r;i++)
    106     {
    107         if(P[i].op==1)
    108             updata(1,P[i].y,0);
    109         P[i]=temp[i];
    110     }
    111 }
    112 void solve()
    113 {
    114     if(pn)
    115     {
    116         //离散化部分 
    117         sort(vy.begin(),vy.end());
    118         for(int i=0;i<vy.size();i++)
    119         {
    120             newy[vy[i]]=i+1;
    121             num[vy[i]]=0;
    122         }
    123         for(int i=0;i<pn;i++)
    124         {
    125             if(P[i].op==1)
    126                 P[i].y=newy[P[i].y];
    127             else
    128                 P[i].y=newy[P[i].y],P[i].y1=newy[P[i].y1];
    129         }
    130         //进行分治 
    131         cdq(0,pn-1);
    132     }
    133     for(int i=0;i<qn;i++)
    134     {
    135         int sum=0;
    136         //判断2^0+2^1+2^2+...+2^50含有哪些 
    137         for(int j=0;j<=50;j++)
    138             if(ans[i]&cf2[j])
    139                 sum++;
    140         printf("%d
    ",sum); 
    141         ans[i]=0;
    142     }
    143     pn=qn=0;
    144     vy.clear();
    145 }
    146 int main()
    147 {
    148     int op,x,y,c,y1;
    149     built(1,1,N);
    150     for(int i=1;i<=50;i++)
    151         cf2[i]=cf2[i-1]<<1;
    152     while(~scanf("%d",&op)&&op!=3)
    153     {
    154         if(op==0)
    155             solve();
    156         else if(op==1)
    157         {
    158             scanf("%d%d%d",&x,&y,&c);
    159             addp(1,x,y,0,cf2[c]);
    160             addy(y);
    161         }
    162         else
    163         {
    164             scanf("%d%d%d",&x,&y,&y1);
    165             addp(2,x,y,y1,qn++);
    166             addy(y);
    167             addy(y1);
    168         }
    169     }
    170     solve();
    171     return 0;
    172 }
    一分二二分四

      但实际上,3个实现方法中,暴力最快。。。数据太坑了

  • 相关阅读:
    url_encode and url_decode in Shell
    学嵌入式技术,做高端电子工程师
    MCU助推居家移动医疗微型化
    深圳单片机培训,7月盛大开班,报名既送
    中国嵌入式工控机市场前景广阔
    嵌入式 现已发展为 IT行业的主流——高薪,且人才缺乏
    谷歌苹果已“技穷”?移动操作系统2013无创新
    C# 与 C++,语法差别有多小-其他2
    link
    C# 与 C++,语法差别有多小-第三章 C++数据类型 第一部分
  • 原文地址:https://www.cnblogs.com/LMCC1108/p/10699522.html
Copyright © 2011-2022 走看看