hdu 4391 块状链表区间操作lazy技巧

块状链表太强大了,也可以实现和线段树一样的lazy操作来提高效率。

每个块维护自己块的信息。

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <cmath>
  5 #include <map>
  6 using namespace std;
  7
  8 const int M = 400;
  9 int b[M][M];
 10 int n, m, ps;
 11 int lazy[M];
 12 map<int, int> mp[M];
 13
 14 void down( int i )
 15 {
 16     if ( lazy[i] == -1 ) return ;
 17     for ( int j = 0; j < ps && i * ps + j < n; j++ )
 18     {
 19         b[i][j] = lazy[i];
 20     }
 21     lazy[i] = -1;
 22 }
 23
 24 int query( int l, int r, int v )
 25 {
 26     int cur = l / ps, ncur = r / ps;
 27     l = l % ps, r = r % ps;
 28     int res = 0;
 29     for ( int i = cur + 1; i < ncur; i++ )
 30     {
 31         if ( mp[i].count(v) )
 32         {
 33             res += mp[i][v];
 34         }
 35     }
 36     if ( cur != ncur )
 37     {
 38         down(cur);
 39         for ( int j = l; j < ps; j++ )
 40         {
 41             if ( b[cur][j] == v ) res++;
 42         }
 43         down(ncur);
 44         for ( int j = 0; j <= r; j++ )
 45         {
 46             if ( b[ncur][j] == v ) res++;
 47         }
 48     }
 49     else
 50     {
 51         down(cur);
 52         for ( int j = l; j <= r; j++ )
 53         {
 54             if ( b[cur][j] == v ) res++;
 55         }
 56     }
 57     return res;
 58 }
 59
 60 void update( int l, int r, int v )
 61 {
 62     int cur = l / ps, ncur = r / ps;
 63     l = l % ps, r = r % ps;
 64     for ( int i = cur + 1; i < ncur; i++ )
 65     {
 66         mp[i].clear();
 67         mp[i][v] = ps;
 68         lazy[i] = v;
 69     }
 70     if ( cur != ncur )
 71     {
 72         down(cur);
 73         for ( int j = l; j < ps; j++ )
 74         {
 75             mp[cur][b[cur][j]]--;
 76             b[cur][j] = v;
 77         }
 78         mp[cur][v] += ps - l;
 79         down(ncur);
 80         for ( int j = 0; j <= r; j++ )
 81         {
 82             mp[ncur][b[ncur][j]]--;
 83             b[ncur][j] = v;
 84         }
 85         mp[ncur][v] += r + 1;
 86     }
 87     else
 88     {
 89         down(cur);
 90         for ( int j = l; j <= r; j++ )
 91         {
 92             mp[cur][b[cur][j]]--;
 93             b[cur][j] = v;
 94         }
 95         mp[cur][v] += r - l + 1;
 96     }
 97 }
 98
 99 int main ()
100 {
101     ps = 350;
102     while ( scanf("%d%d", &n, &m) != EOF )
103     {
104         memset( lazy, -1, sizeof(lazy) );
105         for ( int i = 0; i < M; i++ ) mp[i].clear();
106         for ( int i = 0; i < n; i++ )
107         {
108             int tmp;
109             scanf("%d", &tmp);
110             b[i / ps][i % ps] = tmp;
111             mp[i / ps][tmp]++;
112         }
113         int a, l, r, z;
114         while ( m-- )
115         {
116             scanf("%d%d%d%d", &a, &l, &r, &z);
117             if ( a == 1 )
118             {
119                 update( l, r, z );
120             }
121             else
122             {
123                 printf("%d\n", query( l, r, z ));
124             }
125         }
126     }
127     return 0;
128 }
时间: 2024-08-27 05:43:02

hdu 4391 块状链表区间操作lazy技巧的相关文章

hdu 1754 块状链表 单点修改+单点查询

经典的线段树题目,也可以用块状链表做. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <cmath> 5 using namespace std; 6 7 const int N = 200000; 8 const int M = 800; 9 int n, m, tot; 10 11 int max( int a, int b ) 12 { 13 retu

hdu 5057 块状链表

没有插入和删除操作... 所以还是很好写的,分块暴力就好了. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <cmath> 5 using namespace std; 6 7 const int N = 400; 8 const int M = 11; 9 int b[N * N]; 10 int cnt[N][M][M]; 11 int w[M]; 12

poj 3468 块状链表 区间修改+区间查询

经典的线段树题目,也可以用块链来做. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <cmath> 5 using namespace std; 6 7 typedef __int64 ll; 8 const ll M = 400; 9 ll b[M][M]; 10 ll add[M]; 11 ll sum[M]; 12 ll n, m, ps; 13 14

hdu 4348 To the moon(主席树区间操作)

题目链接:hdu 4348 To the moon 题意: 给你n个数,有m个操作. 1.给区间[l,r]的所有数+d,并且时间戳+1 2.询问当前时间戳的区间和. 3.询问过去时间戳t的区间和. 4.退回到时间戳t. 题解: 直接上主席树. 不过区间操作的时候push_down空间似乎不是那么够用. 所有把push_down这个操作去掉. 用一个标记记录当前这个区间的累加. 询问的时候就将这个累加传下去.(具体看代码) 最后还有退回状态t的时候可以把cnt=root[t+1], 因为后面的内存

HDU 3911 Black And White (线段树区间合并 + lazy标记)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3911 给你n个数0和1,m个操作: 0操作  输出l到r之间最长的连续1的个数 1操作  将l到r之间的0变1,1变0 区间合并的模版题,结构体中的lsum1表示从此区间最左端开始连续1的个数,rsum1表示从此区间最右端开始连续1的个数,sum1表示此区间连续1的个数最长是多少.lsum0,rsum0,sum0也是如此.每一次1的操作将区间内lazy标记与1异或一次,异或两次就说明操作抵消了.然后

HDU 4578 线段树区间更新(确定区间操作的优先级)

HDU 4578 线段树区间更新 操作有: 区间所有数add(c) 区间所有数mul(c) 区间所有数set(c) 查询有: 区间所有数的p次方和(p>= 1 && p <= 3) 关键是区间更新的三种操作的优先级的确定清楚set>mul>add 关键是:down和update中对区间的更新操作是一回事,可以写成函数方便编程 //#pragma warning (disable: 4786) //#pragma comment (linker, "/STA

【块状链表】【权值分块】bzoj3065 带插入区间K小值

显然是块状链表的经典题.但是经典做法的复杂度是O(n*sqrt(n)*log(n)*sqrt(log(n)))的,出题人明确说了会卡掉. 于是我们考虑每个块内记录前n个块的权值分块. 查询的时候差分什么的,复杂度就是O(n*sqrt(n))的了. 插入的时候为了防止块过大,要考虑裂块(细节较多). 感谢bzoj提供O2,我的STL块链才能通过(list+vector). #include<cstdio> #include<list> #include<vector> #

【BZOJ2741】【块状链表+可持久化trie】FOTILE模拟赛L

Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r. 为了体现在线操作,对于一个询问(x,y): l = min ( ((x+lastans) mod N)+1 , ((y+lastans) mod N)+1 ).r = max ( ((x+lastans) mod N)+1 , ((y+last

c++之路——块状链表(教主的魔法)

F.A.Qs Home Discuss ProblemSet Status Ranklist Contest ModifyUser  gryz2016 Logout 捐赠本站 Notice:由于本OJ建立在Linux平台下,而许多题的数据在Windows下制作,请注意输入.输出语句及数据类型及范围,避免无谓的RE出现. 3343: 教主的魔法 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 711  Solved: 309[Submit][Stat