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("\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 }