【CodeForces】455D Serega and Fun 双向链表分块暴力

来源:互联网 发布:linux exe 用什么命令 编辑:程序博客网 时间:2024/06/05 16:12

传送门:【CodeForces】455D Serega and Fun


题目分析:

看大神各种splay高效过之。。。实在无力啊。。。只会分块暴力搞了。。。

具体思路是这样的:

首先我们将整个数组用双向链表模拟,对于所有元素x,设L[x]为他实际上左边的元素,R[x]为他实际上右边的元素,然后将其分块,分块系数自己定。。设H[x]指向第x块开头的元素。

由于CF能开大数组的特性。。我们直接开块数*数组长度的二维大数组保存该块中某个元素的个数。

每次操作,我们先确定l和r所在的块,然后确定l和r在各自对应的块中相对于块中头元素的位移,然后暴力推出该位置对应的元素。设l位置上的元素为 ll ,r上的元素为 rr 。

对于操作一,如果l == r则直接不执行(我的可能会出一点问题,解决比较繁琐还不如直接特判)。设 ll 所在的块编号为pos_l, rr 所在的块编号为pos_r,将所有pos_l+1到pos_r的H[ i ]指向L[H[ i ]],即将 l 到 r 内所有的元素右移一位,也可以理解为将整个需要变动的块左移一位,然后执行删除元素 rr 的操作,再然后将其插入到 ll 的左边,并且如果 ll 正好是某个块的头元素,那么将该块的H[ ]指向rr。不要忘记修改元素在对应块中的计数!

对于操作二,暴力统计 ll 所在区间内k的个数以及 rr所在区间内k的个数(因为我们每个块保存的是整个块内k的个数,不能直接得到这个块内部分区间内k的个数),对于夹在中间的块,直接加上该块内k的个数即可。


分块题我觉得精髓在于调整分块系数。。。本题如果用n^0.5作为系数则能勉强过掉。。但是如果用n^0.618可以不到1000ms就搞定。。。


双向链表(双端队列)+分块,队友提了一下,很不错的想法!然后我们各自实现了一个,他是STL,我是自己模拟双向链表,STL跑的比直接模拟的要快,应该是STL里面有什么效率比较好的元素吧。。写了将近半天,能过掉真的很开心啊,不过话说一开始map直接TLE了。。。果然在CF平台上还是大数组靠谱。。


代码如下:


#include <map>#include <cmath>#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;#define REP( i , a , b ) for ( int i = a ; i < b ; ++ i )#define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i )#define REV( i , a , b ) for ( int i = a ; i >= b ; -- i )#define CLR( a , x ) memset ( a , x , sizeof a )const int SQR = 330 ;const int MAXN = 100005 ;int cnt[SQR][MAXN] ;int L[MAXN] , R[MAXN] , H[SQR] ;int a[MAXN] ;int sqr ;int last_ans ;int n , m ;void solve () {int ch , l , r , k , x ;last_ans = 0 ;sqr = pow ( n , 0.618 ) ;//CLR ( cnt , 0 ) ;FOR ( i , 1 , n ) {scanf ( "%d" , &a[i] ) ;++ cnt[( i - 1 ) / sqr][a[i]] ;L[i] = i - 1 ;R[i] = i + 1 ;}L[1] = R[n] = -1 ;FOR ( i , 0 , n / sqr ) H[i] = i * sqr + 1 ;scanf ( "%d" , &m ) ;REP ( _ , 0 , m ) {scanf ( "%d%d%d" , &ch , &l , &r ) ;l = ( l + last_ans - 1 ) % n + 1 ;r = ( r + last_ans - 1 ) % n + 1 ;if ( l > r ) swap ( l , r ) ;if ( ch == 1 && l == r ) continue ;int pos_l = ( l - 1 ) / sqr ;//l所在的块int pos_r = ( r - 1 ) / sqr ;//r所在的块int ll = H[pos_l] ;//l所在的块的头元素int rr = H[pos_r] ;//r所在的块的头元素l -= pos_l * sqr ;//l相对于所在块头元素的位移r -= pos_r * sqr ;//r相对于所在块头元素的位移REP ( i , 1 , l ) ll = R[ll] ;//找到l所在的位置对应的元素REP ( i , 1 , r ) rr = R[rr] ;//找到r所在的位置对应的元素if ( ch == 1 ) {-- cnt[pos_r][a[rr]] ;//将元素rr从所在块删除++ cnt[pos_l][a[rr]] ;//将元素rr添加到ll所在的块if ( ll == H[pos_l] ) H[pos_l] = rr ;//如果ll正好是块头,那么该块的头部指针指向rrREV ( i , pos_r , pos_l + 1 ) {H[i] = L[H[i]] ;//将该块的左边块的最右端的元素添加到该块-- cnt[i - 1][a[H[i]]] ;//将该块左端的最右端的元素从左端删除++ cnt[i][a[H[i]]] ;//将该块左端的最右端的元素添加到该块的左端开头}//将rr从pos_r中删除R[L[rr]] = R[rr] ;L[R[rr]] = L[rr] ;//将rr添加到ll的左边L[rr] = L[ll] ;R[rr] = ll ;R[L[ll]] = rr ;L[ll] = rr ;/*for ( int i = H[0] ; ~i ; i = R[i] )printf ( "%d-" , a[i] ) ;printf ( "\n" ) ;for ( int i = 0 ; i <= sqr ; ++ i )printf ( "H[%d] = %d : %d\n" , i , H[i] , a[H[i]] ) ;*/} else {scanf ( "%d" , &k ) ;k = ( k + last_ans - 1 ) % n + 1 ;int ans = 0 ;if ( pos_l == pos_r ) {for ( int i = ll ; i != R[rr] ; i = R[i] ) if ( a[i] == k ) ans ++ ;} else {for ( int i = L[H[pos_l + 1]] ; i != L[ll] ; i = L[i] ) if ( a[i] == k ) ans ++ ;for ( int i = H[pos_r] ; i != R[rr] ; i = R[i] ) if ( a[i] == k ) ans ++ ;REP ( i , pos_l + 1 , pos_r ) ans += cnt[i][k] ;}printf ( "%d\n" , ans ) ;last_ans = ans ;}}}int main () {while ( ~scanf ( "%d" , &n ) )solve () ;return 0 ;}


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 肉罐头拉环断了怎么办 5大战区拥兵自重怎么办 买的期房停工了怎么办 怀孕后长了副乳怎么办 耳朵冻的红肿了怎么办 吃螃蟹吃柿子了怎么办 吃了螃蟹和柿子怎么办 螃蟹与柿子同吃怎么办 手被鞭炮炸伤了怎么办 索尼l36h变砖了怎么办 oppor9s手机忘记解锁图案怎么办 索尼z5刷死机了怎么办 魅蓝note3被锁定怎么办 oppo图案锁忘了怎么办 手机图案锁忘w怎么办输 手机图案解锁密码忘了怎么办 忘记htc手机锁屏怎么办 我手机密码忘了怎么办 小米5x忘记密码怎么办 oppo忘记手机解锁图案怎么办 手机解锁图案忘了怎么办 苹果id给锁了怎么办 苹果手机忘了ld怎么办 4s忘记开机密码怎么办 取卵22个肚子胀怎么办 夜神模拟器很卡怎么办 夜神模拟器卡顿怎么办 入职体检有痔疮怎么办 泰迪鼻子干怎么办恢复 泰迪幼犬鼻子干怎么办 狗狗呕吐没精神怎么办 狗狗鼻子干拉稀怎么办 狗狗鼻子干呕吐怎么办 肛门直肠环断了怎么办 原房主欠取暖费怎么办 澳门赢了几千万怎么办 被海鲜骗局骗了怎么办 将军令没电了怎么办 将军令没有电了怎么办 在香港超过7天怎么办 肩膀上的灯灭了怎么办