• Gym 101911E "Painting the Fence"(线段树区间更新+双端队列)


    传送门

    题意:

      庭院中有 n 个围栏,每个围栏上都被涂上了不同的颜色(数字表示);

      有 m 条指令,每条指令给出一个整数 x ,你要做的就是将区间[ x第一次出现的位置 , x最后出现的位置 ]中的围栏

      全部涂成 x ,经过 m 次操作后,输出每个围栏的涂色情况;

    题解:

      比赛的时,在读完题后,一瞬间,想到了线段树的区间更新,懒惰标记,but 我已经好久好久没写过线段树的代码了(嫌代码太长,逃);

      所以,比赛时,就不了了之,去看其他题了;

      今天,温习了一下线段树的用法,重新思考了本题的解题思路,感觉,线段树可以做出来;

      然后,对着电脑撸了一个线段树版的代码,一发AC,哈哈,开森~~~~~~

      手动艾特两个不相信线段树可以AC的童鞋,哈哈哈!

      

      具体思路:

      首先准备一个双端队列 q[ maxn ]; (maxn = 3e5+50 ,因为 ci ≤ 3*105

      q[ i ] 中存储的是所有的被涂上颜色 i 的栅栏编号,按顺序从小到大存储;

      对于每一个指令 x ,首先判断 q[x].size() 是否大于 1,如果大于 1,令 f = q[x].front() , e = q[x].end();

      然后,判断下标 f 和 e 对应的栅栏的颜色是否为 x ,如果是,通过线段树的区间更新+懒惰标记将区间[f,e]染成 x,接着执行下一条指令;

      如果 f 或 e 对应的栅栏颜色在之前被涂成了其他颜色,那么在 q[x] 中查找下一个满足条件的区间,如果找不到,不操作,执行下一条指令;

      最后,调用线段树的查询操作,输出答案。

    AC代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<deque>
      4 using namespace std;
      5 #define ls(x) (x<<1)
      6 #define rs(x) (x<<1|1)
      7 const int maxn=3e5+50;
      8 
      9 int n,m;
     10 int a[maxn];
     11 deque<int >q[maxn];
     12 struct SegmentTree
     13 {
     14     int l,r;
     15     int color;
     16     int mid()
     17     {
     18         return l+((r-l)>>1);
     19     }
     20 }segTree[4*maxn];
     21 
     22 void buildSegTree(int pos,int l,int r)
     23 {
     24     segTree[pos].l=l;
     25     segTree[pos].r=r;
     26     segTree[pos].color=0;
     27     if(l == r)
     28     {
     29         segTree[pos].color=a[l];
     30         return ;
     31     }
     32 
     33     int mid=l+((r-l)>>1);
     34     buildSegTree(ls(pos),l,mid);
     35     buildSegTree(rs(pos),mid+1,r);
     36 }
     37 
     38 /**
     39     向下更新,与区间更新懒惰标记不同的是
     40     直接将pos的左右儿子的color赋值为x
     41 */
     42 void pushDown(int pos)
     43 {
     44     int &x=segTree[pos].color;
     45     if(x != 0)
     46     {
     47         segTree[ls(pos)].color=x;
     48         segTree[rs(pos)].color=x;
     49         x=0;
     50     }
     51 }
     52 /**
     53     将区间[l,r]所包含的子区间的color值赋为x
     54     出现的bug:起初直接将64行的赋值操作写成了
     55     segTree[pos].color=a[l];
     56     调试了好大会;
     57     因为 a[l] 是改变前的涂色情况,如果l号栅栏在之前被染成了其他颜色
     58     那么l号栅栏的颜色就不是a[l]了
     59 */
     60 void Update(int pos,int l,int r,int x)
     61 {
     62     if(l <= segTree[pos].l && r >= segTree[pos].r)
     63     {
     64         segTree[pos].color=x;
     65         return ;
     66     }
     67     pushDown(pos);
     68 
     69     int mid=segTree[pos].mid();
     70     if(r <= mid)
     71         Update(ls(pos),l,r,x);
     72     else if(l > mid)
     73         Update(rs(pos),l,r,x);
     74     else
     75     {
     76         Update(ls(pos),l,mid,x);
     77         Update(rs(pos),mid+1,r,x);
     78     }
     79 }
     80 int Query(int pos,int index)
     81 {
     82     if(segTree[pos].l == segTree[pos].r)
     83         return segTree[pos].color;
     84 
     85     pushDown(pos);
     86 
     87     int mid=segTree[pos].mid();
     88     if(index <= mid)
     89         return Query(ls(pos),index);
     90     else
     91         return Query(rs(pos),index);
     92 }
     93 void Solve()
     94 {
     95     buildSegTree(1,1,n);
     96     for(int i=1;i <= m;++i)
     97     {
     98         int x;
     99         scanf("%d",&x);
    100         if(q[x].size() <= 1)
    101             continue;
    102 
    103         /**
    104             寻找可行的区间[f,e]
    105         */
    106         int f=q[x].front();
    107         int e=q[x].back();
    108         while(Query(1,f) != x && !q[x].empty())
    109         {
    110             q[x].pop_front();
    111             if(!q[x].empty())
    112                 f=q[x].front();
    113         }
    114         while(Query(1,e) != x && !q[x].empty())
    115         {
    116             q[x].pop_back();
    117             if(!q[x].empty())
    118                 e=q[x].back();
    119         }
    120         //确保f != e
    121         if(q[x].size() > 1)
    122             Update(1,f,e,x);
    123     }
    124     for(int i=1;i <= n;++i)
    125         printf("%d ",Query(1,i));
    126     printf("
    ");
    127 }
    128 int main()
    129 {
    130 //    freopen("C:/Users/hyacinthLJP/Desktop/stdin/contest","r",stdin);
    131     scanf("%d",&n);
    132     for(int i=1;i <= n;++i)
    133     {
    134         scanf("%d",a+i);
    135         q[a[i]].push_back(i);
    136     }
    137     scanf("%d",&m);
    138     Solve();
    139 
    140     return 0;
    141 }
    View Code
  • 相关阅读:
    (转)C++ typename的起源与用法
    EOS智能合约深度解析
    cmake常用变量和命令解析
    (转)Linux下source命令详解
    eosio_install.sh执行过程
    java之collection总结
    Guava之RangeMap
    java file.listFiles()按文件名称、日期、大小排序
    Java下载文件的几种方式
    Java泛型Class<T>、T与Class<?>
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/10512684.html
Copyright © 2020-2023  润新知