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

传送门

题意:

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

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

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

题解:

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

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

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

  然后,对着电脑撸了一个线段树版的代码,一发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("\n");
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

猜你喜欢

转载自www.cnblogs.com/violet-acmer/p/10512684.html
今日推荐