zoukankan      html  css  js  c++  java
  • [SCOI2010]序列操作

    嘟嘟嘟

     

    这一看都知道,肯定是线段树,只不过这个稍微有些复杂……

    首先对于操作0和1都是很好办的,比较简单的区间修改。然后查询区间多少个1,就是区间和,也好办。

    至于查询连续个1,做过酒店的都知道怎么办,维护一个imax[now](imax是interval's max,不是电影……):区间连续的1是多少个,lmax[now]:从now区间的左端点开始有多少个连续的1,rmax[now]从右端点开始有多少连续个1,这样区间合并的时候就是imax[now] = max(imax[now << 1], imax[now << 1 | 1], rmax[now << 1] + lmax[now << 1 | 1]).

    查询酒店那道题没讲。对于要找的区间[L, R],如果各有一部分在当前区间的左右儿子中,那么分三种情况:1.在左儿子中,那么递归下去。1.在右儿子中,同样递归下去。3.最优解可能一部分在左儿子中,一部分在右儿子中,然而不能直接返回 t[now << 1].rmax +t[now << 1 |1].lmax,因为还有当前要找的区间的限制,因此是min(t[now << 1].rmax1, mid - L + 1) + min(t[now << 1| 1].lmax1, R - mid - 1 + 1)。然后这三种情况取max返回。

    最后有解决的是区间反转问题,也是开一个标记(我就叫lzy_re了),他的优先级是比区间修改的优先级低的,因为若果一个区间都改成了0 / 1,那么这个区间之前的反转就没有用了,所以pushdown的时候,先把lazy往下传,再把lzy_re往下传。

    这样的话要维护区间最长的1和0了,这样反转的时候只用把1和0维护的信息交换即可。

    一个技巧就是在pushup的时候,可以重定义 '+' 号,这样用结构体的时候在结构体里面写就行,然后外面直接写一个 t[now] = t[now << 1] + t[now << 1 | 1] 就行了。

    具体的细节看代码

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<algorithm>
      4 #include<cmath>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<stack>
      8 #include<queue>
      9 #include<vector>
     10 #include<cctype>
     11 using namespace std;
     12 #define enter puts("")
     13 #define space putchar(' ')
     14 #define Mem(a) memset(a, 0, sizeof(a))
     15 typedef long long ll;
     16 typedef double db;
     17 const int INF = 0x3f3f3f3f;
     18 const db eps = 1e-8;
     19 const int maxn = 1e5 + 5;
     20 inline ll read()
     21 {
     22     ll ans = 0;
     23     char ch = getchar(), last = ' ';
     24     while(!isdigit(ch)) {last = ch; ch = getchar();}
     25     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
     26     if(last == '-') ans = -ans;
     27     return ans;
     28 }
     29 inline void write(ll x)
     30 {
     31     if(x < 0) putchar('-'), x = -x;
     32     if(x >= 10) write(x / 10);
     33     putchar(x % 10 + '0');
     34 }
     35 
     36 int n, m;
     37 
     38 struct Tree
     39 {
     40     int l, r, sum, lzy, lzy_re;
     41     int lmax0, rmax0, imax0, lmax1, rmax1, imax1;
     42     Tree operator + (const Tree& other)const
     43     {
     44         Tree ret;
     45         ret.l = l; ret.r = other.r;        //这个别忘了 
     46         ret.sum = sum + other.sum;
     47         ret.lzy = -1; ret.lzy_re = 0;    //因为pushup操作在pushdown之后,所以此时所有标记已清空 
     48         ret.lmax0 = lmax0;
     49         if(lmax0 == r - l + 1) ret.lmax0 += other.lmax0;    //以下是维护区间最长的0和1,思路详见酒店那道题 
     50         ret.rmax0 = other.rmax0;
     51         if(other.rmax0 == other.r - other.l + 1) ret.rmax0 += rmax0;
     52         ret.imax0 = max(rmax0 + other.lmax0, max(imax0, other.imax0));
     53         ret.lmax1 = lmax1;
     54         if(lmax1 == r - l + 1) ret.lmax1 += other.lmax1;
     55         ret.rmax1 = other.rmax1;
     56         if(other.rmax1 == other.r - other.l + 1) ret.rmax1 += rmax1;
     57         ret.imax1 = max(rmax1 + other.lmax1, max(imax1, other.imax1));
     58         return ret;        
     59     }
     60 }t[maxn << 2];
     61 
     62 void build(int L, int R, int now)
     63 {
     64     t[now].l = L; t[now].r = R;
     65     if(L == R)
     66     {
     67         t[now].sum = read(); t[now].lzy = -1; t[now].lzy_re = 0;        //lzy初值最好设成-1,因为每一个数是0 / 1,初值为0不好判断 
     68         t[now].lmax0 = t[now].rmax0 = t[now].imax0 = t[now].sum ^ 1;     
     69         t[now].lmax1 = t[now].rmax1 = t[now].imax1 = t[now].sum;
     70         return;
     71     }
     72     int mid = (L + R) >> 1;
     73     build(L, mid, now << 1);
     74     build(mid + 1, R, now << 1 | 1);
     75     t[now] = t[now << 1] + t[now << 1 | 1];
     76 }
     77 void pushdown(int now)
     78 {
     79     if(t[now].lzy != -1)    //先传区间修改 
     80     {
     81         t[now << 1].sum = (t[now << 1].r - t[now << 1].l + 1) * t[now].lzy;    //左区间 
     82         t[now << 1].lzy = t[now].lzy;
     83         t[now << 1].lzy_re = 0;        //他的左右儿子区间的反转标记得清零 
     84         t[now << 1].lmax0 = t[now << 1].rmax0 = t[now << 1].imax0 = t[now << 1].lzy ? 0 : t[now << 1].r - t[now << 1].l + 1;
     85                                     //刚开始写成了 = t[now].sum * (t[now].lzy ^ 1),显然不对呀…… 
     86         t[now << 1].lmax1 = t[now << 1].rmax1 = t[now << 1].imax1 = t[now << 1].sum;        
     87         
     88         t[now << 1 | 1].sum = (t[now << 1 | 1].r - t[now << 1 | 1].l + 1) * t[now].lzy;    //右区间 
     89         t[now << 1 | 1].lzy = t[now].lzy;
     90         t[now << 1 | 1].lzy_re = 0;
     91         t[now << 1 | 1].lmax0 = t[now << 1 | 1].rmax0 = t[now << 1 | 1].imax0 = t[now << 1 | 1].lzy ? 0 : t[now << 1 | 1].r - t[now << 1 | 1].l + 1;
     92         t[now << 1 | 1].lmax1 = t[now << 1 | 1].rmax1 = t[now << 1 | 1].imax1 = t[now << 1 | 1].sum;
     93         t[now].lzy = -1;
     94     }
     95     if(t[now].lzy_re)
     96     {
     97         t[now << 1].sum = t[now << 1].r - t[now << 1].l + 1 - t[now << 1].sum;
     98         t[now << 1].lzy_re ^= 1;        
     99         //注意一定要 ^ 1,而不是直接 = 1,因为很显然的是反转两次就还是原状。这就体现了lzy_re初值为0而不是-1的好处 
    100         swap(t[now << 1].lmax0, t[now << 1].lmax1); swap(t[now << 1].rmax0, t[now << 1].rmax1); 
    101         swap(t[now << 1].imax0, t[now << 1].imax1);        //直接把维护最长的0和1这俩的信息交换就行 
    102         
    103         t[now << 1 | 1].sum = t[now << 1 | 1].r - t[now << 1 | 1].l + 1 - t[now << 1 | 1].sum;
    104         t[now << 1  | 1].lzy_re ^= 1;        //注意不是直接等于1 
    105         swap(t[now << 1 | 1].lmax0, t[now << 1 | 1].lmax1); swap(t[now << 1 | 1].rmax0, t[now << 1 | 1].rmax1); 
    106         swap(t[now << 1 | 1].imax0, t[now << 1 | 1].imax1);
    107         t[now].lzy_re = 0;
    108     }
    109 }
    110 void update_all(int L, int R, int now, bool d)
    111 {
    112     if(t[now].l == L && t[now].r == R)
    113     {
    114         t[now].sum = (R - L + 1) * d;
    115         t[now].lzy = d;
    116         t[now].lzy_re = 0;
    117         t[now].lmax0 = t[now].rmax0 = t[now].imax0 = d ? 0 : R - L + 1;
    118         t[now].lmax1 = t[now].rmax1 = t[now].imax1 = t[now].sum;
    119         return;
    120     }
    121     pushdown(now);
    122     int mid = (t[now].l + t[now].r) >> 1;
    123     if(R <= mid) update_all(L, R, now << 1, d);
    124     else if(L > mid) update_all(L, R, now << 1 | 1, d);
    125     else update_all(L, mid, now << 1, d), update_all(mid + 1, R, now << 1 | 1, d);
    126     t[now] = t[now << 1] + t[now << 1 | 1];
    127 }
    128 void update_re(int L, int R, int now)    
    129 {
    130     if(t[now].l == L && t[now].r == R)
    131     {
    132         t[now].sum = R - L + 1 - t[now].sum;
    133         t[now].lzy_re ^= 1;
    134         swap(t[now].lmax0, t[now].lmax1); swap(t[now].rmax0, t[now].rmax1); 
    135         swap(t[now].imax0, t[now].imax1);
    136         return;
    137     }                
    138     pushdown(now);
    139     int mid = (t[now].l + t[now].r) >> 1;
    140     if(R <= mid) update_re(L, R, now << 1);
    141     else if(L > mid) update_re(L, R, now << 1 | 1);
    142     else update_re(L, mid, now << 1), update_re(mid + 1, R, now << 1 | 1);
    143     t[now] = t[now << 1] + t[now << 1 | 1];
    144 }
    145 int query_sum(int L, int R, int now)
    146 {
    147     if(t[now].l == L && t[now].r == R) return t[now].sum;
    148     pushdown(now);
    149     int mid = (t[now].l + t[now].r) >> 1;
    150     if(R <= mid) return query_sum(L, R, now << 1);
    151     else if(L > mid) return query_sum(L, R, now << 1 | 1);
    152     else return query_sum(L, mid, now << 1) + query_sum(mid + 1, R, now << 1 | 1);    
    153 }
    154 int query_max(int L, int R, int now)
    155 {
    156     if(t[now].l == L && t[now].r == R) return t[now].imax1;
    157     pushdown(now);
    158     int mid = (t[now].l + t[now].r) >> 1;
    159     if(R <= mid) return query_max(L, R, now << 1);
    160     else if(L > mid) return query_max(L, R, now << 1 | 1);
    161     else            //最大值分三种情况 
    162     {
    163         int ret1 = max(query_max(L, mid, now << 1), query_max(mid + 1, R, now << 1 | 1));    //分别在左右区间 
    164         int ret2 = min(t[now << 1].rmax1, mid - L + 1) + min(t[now << 1| 1].lmax1, R - mid - 1 + 1);    //在两区间都有
    165         //刚开始写成 min(t[now << 1].rmax1, L) + min(t[now << 1| 1].lmax1, R),因为比较的是长度,而L, R是端点,自然就不对了 
    166         return max(ret1, ret2);
    167     }
    168 }
    169 
    170 int main()
    171 {
    172     n = read(); m = read();
    173     build(0, n - 1, 1);
    174     for(int i = 1; i <= m; ++i)
    175     {
    176         int d = read(), L = read(), R = read();
    177         if(d == 0) update_all(L, R, 1, 0);
    178         else if(d == 1) update_all(L, R, 1, 1);
    179         else if(d == 2) update_re(L, R, 1);
    180         else if(d == 3) write(query_sum(L, R, 1)), enter;
    181         else write(query_max(L, R, 1)), enter;
    182     }
    183     return 0;
    184 }
    View Code
  • 相关阅读:
    HashMap源码解读(转)
    使用javascript开发2048
    程序猿接私活经验总结,来自csdn论坛语录
    Cocos2d-x实例:设置背景音乐与音效- AppDelegate实现
    Jenkins(二)
    SVN高速新手教程
    Visio Premium 2010密钥+破解激活方法
    oracle中LAG()和LEAD()等分析统计函数的使用方法(统计月增长率)
    shell语法简单介绍
    memset函数具体说明
  • 原文地址:https://www.cnblogs.com/mrclr/p/9502905.html
Copyright © 2011-2022 走看看