zoukankan      html  css  js  c++  java
  • 【POJ 2777 】 线段树之成段更新+位运算

    题目链接:http://poj.org/problem?id=2777

    题目大意:  给你一段区间[1,L] ,  给定初始所有节点颜色为1,有下面两种操作:

    1、 “C A B D”  将区间[A,B]改变颜色为D。

    2、“P A B” 计算区间[A,B]有多少种不同的颜色。

    解题思路:

        最土的可能100000个节点*100000次运算,暴力肯定TLE。解决这一类题目一般会想到线段树或者树状数组,这里用线段树。

       这里每次改变都从根节点到叶子节点都同步更新的话肯定TLE,这里又要用到区间更新。

       区间更新:   区间更新指的是当要改变某个区间[tl,tr]的颜色值,当往下递归到这个区间[l,r]包含在[tl,tr]里面就停止,将要改变的颜色值赋给这个区间,并做一次标记。这个标记的作用防止下次不会再更新这里了,我们查询的时候就可以以标记为判断要不要询问这里的值,而如果下次更新又再次来到这里,就会把先前更新的值给覆盖掉,变为这次更新的值,而与之同步的是上次标记的值会继续往下传,往下传完之后此节点的标记清空。往下传的节点会继续往下传,一直传到此次和上次更新的区间不一样就停止,道理同上。

       本题还用到了或位运算。我们用1的个数表示区间不同颜色的种类,则tree[u]=tree[2*u] | tree[2*u+1];

       搞错了一下位运算,纠结了良久。  1<<val   往哪边进行位运算1就在哪边。

        线段树好题。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstdlib>
      4 #include <algorithm>
      5 #include <cstring>
      6 using namespace std;
      7 
      8 const int maxn=100005;
      9 int flag[4*maxn];
     10 int tree[4*maxn];
     11 
     12 void down(int u)   ///往下传标记
     13 {
     14     if(flag[u])
     15     {
     16         flag[2*u]=flag[u];
     17         flag[2*u+1]=flag[u];
     18         tree[2*u]=tree[u];
     19         tree[2*u+1]=tree[u];
     20         flag[u]=0;
     21     }
     22 }
     23 
     24 void build(int u, int l, int r)  ///建树
     25 {
     26     flag[u]=0;
     27     tree[u]=(1<<1);
     28     if(l==r)
     29         return ;
     30     int mid=(l+r)>>1;
     31     build(2*u,l,mid);
     32     build(2*u+1,mid+1,r);
     33 }
     34 
     35 void update(int u, int l, int r, int tl, int tr, int val)
     36 {
     37     if(tl<=l&&r<=tr)
     38     {
     39         flag[u]=val;
     40         tree[u]=(1<<val);  ///这里搞错了位运算,写成了(val<<1),纠结了良久
     41         return ;
     42     }
     43     down(u);
     44     int mid=(l+r)>>1;
     45     if(tr<=mid)  update(2*u,l,mid,tl,tr,val);
     46     else if(tl>mid) update(2*u+1,mid+1,r,tl,tr,val);
     47     else
     48     {
     49         update(2*u,l,mid,tl,tr,val);
     50         update(2*u+1,mid+1,r,tl,tr,val);
     51     }
     52     tree[u]=tree[2*u]|tree[2*u+1];
     53 }
     54 
     55 int getsum(int u, int l, int r, int tl, int tr)
     56 {
     57     if(tl<=l&&r<=tr)
     58     {
     59         return  tree[u];
     60     }
     61     down(u);
     62     int mid=(l+r)>>1;
     63     if(tr<=mid)  return getsum(2*u,l,mid,tl,tr);
     64     else if(tl>mid) return getsum(2*u+1,mid+1,r,tl,tr);
     65     else
     66     {
     67         int t1=getsum(2*u,l,mid,tl,tr);
     68         int t2=getsum(2*u+1,mid+1,r,tl,tr);
     69         return t1|t2;
     70     }
     71 }
     72 
     73 int fx(int x)
     74 {
     75     int ans=0;
     76     while(x)
     77     {
     78         if(x&1) ans++;
     79         x>>=1;
     80     }
     81     return ans;
     82 }
     83 
     84 int main()
     85 {
     86     int  n, t, Q;
     87     while(~scanf("%d%d%d",&n,&t,&Q))
     88     {
     89         build(1,1,n);
     90         char ch[3];
     91         while(Q--)
     92         {
     93             scanf("%s",ch);
     94             int l, r, val;
     95             if(ch[0]=='C')
     96             {
     97                 scanf("%d%d%d",&l,&r,&val);
     98                 if(l>r) swap(l,r);
     99                 update(1,1,n,l,r,val);
    100             }
    101             else
    102             {
    103                 scanf("%d%d",&l,&r);
    104                 if(l>r) swap(l,r);
    105                 int ans=getsum(1,1,n,l,r);
    106                 printf("%d\n",fx(ans));
    107             }
    108         }
    109     }
    110     return 0;
    111 }
  • 相关阅读:
    Node.js中,获取req请求的原始IP
    socket原理详解
    让Redis在你的系统中发挥更大作用
    Redis复制与可扩展集群搭建【转】
    Linux下查看日志用到的常用命令
    Linux curl命令详解
    Linux 系统结构详解【转】
    网络IO之阻塞、非阻塞、同步、异步总结
    消息队列设计精要【转】
    MySQL的DDL语句、DML语句与DCL语句
  • 原文地址:https://www.cnblogs.com/kane0526/p/2824081.html
Copyright © 2011-2022 走看看