bzoj2120 数颜色 分块
2016-02-05 22:38
405 查看
据说暴力可过2200ms。。。然而我写分块也才1200ms。。然而很多人写分块跑不过暴力。。。
参考了将狼踩尽(/article/5206358.html)的思路。假设分为m块(注意不是每块m个)。用sum[x][y][z]表示在块x~y中颜色z(经过离散化以后)的个数,val[x][y]表示在x~y块中不同颜色的个数。这样应该就比较容易明白了。
修改:看u会影响那些val[x][y],然后根据sum的值得到val是否要加减,具体看代码;
查询:不能简单的像普通的分块那样进行,要利用现有的。比如查询x~y,它经过的完整的块是u~v,那么我们就可以假设将x~u以及v~y中的颜色插入到val[u][v]中,然后就可以根据修改的模式进行查询了,答案就是val[u][v]。但是最后要复原。
初始化时间复杂度为O(m^2N),修改时最坏经过O(m^2)次,查询主要是零碎部分O(N/m)。总的时间复杂度O(m^2N+M(m^2+N/m)),可以看到,当m=N^(1/3)时时间复杂度最小为O(N^(5/3))。
AC代码如下:
by lych
2016.2 5
参考了将狼踩尽(/article/5206358.html)的思路。假设分为m块(注意不是每块m个)。用sum[x][y][z]表示在块x~y中颜色z(经过离散化以后)的个数,val[x][y]表示在x~y块中不同颜色的个数。这样应该就比较容易明白了。
修改:看u会影响那些val[x][y],然后根据sum的值得到val是否要加减,具体看代码;
查询:不能简单的像普通的分块那样进行,要利用现有的。比如查询x~y,它经过的完整的块是u~v,那么我们就可以假设将x~u以及v~y中的颜色插入到val[u][v]中,然后就可以根据修改的模式进行查询了,答案就是val[u][v]。但是最后要复原。
初始化时间复杂度为O(m^2N),修改时最坏经过O(m^2)次,查询主要是零碎部分O(N/m)。总的时间复杂度O(m^2N+M(m^2+N/m)),可以看到,当m=N^(1/3)时时间复杂度最小为O(N^(5/3))。
AC代码如下:
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> using namespace std; int n,m,size,cnt,tot,blg[20005],a[20005],f[1000005],l[30],r[30],sum[30][30][20005],val[30][30]; void qry(int x,int y){ int i,u=blg[x]+1,v=blg[y]-1; for (i=x; i<l[u] && i<=y; i++){ if (!sum[u][v][a[i]]) val[u][v]++; sum[u][v][a[i]]++; } for (i=y; i>r[v] && i>=x; i--){ if (!sum[u][v][a[i]]) val[u][v]++; sum[u][v][a[i]]++; } printf("%d\n",val[u][v]); for (i=x; i<l[u] && i<=y; i++){ sum[u][v][a[i]]--; if (!sum[u][v][a[i]]) val[u][v]--; } for (i=y; i>r[v] && i>=x; i--){ sum[u][v][a[i]]--; if (!sum[u][v][a[i]]) val[u][v]--; } } int main(){ scanf("%d%d",&n,&m); int i,j,k; size=(int)pow(n,2.0/3); cnt=n/size; for (i=1; i<=cnt; i++){ l[i]=r[i-1]+1; r[i]=l[i]+size-1; } if (r[cnt]<n) r[cnt]=n; for (i=1; i<=n; i++){ scanf("%d",&k); if (!f[k]) f[k]=++tot; a[i]=f[k]; } for (i=1; i<=cnt; i++) for (j=l[i]; j<=r[i]; j++) blg[j]=i; for (i=1; i<=cnt; i++) for (j=i; j<=cnt; j++) for (k=l[i]; k<=r[j]; k++){ if (!sum[i][j][a[k]]) val[i][j]++; sum[i][j][a[k]]++; } while (m--){ char ch=getchar(); while (ch<'A' || ch>'Z') ch=getchar(); int x,y; scanf("%d%d",&x,&y); if (ch=='Q') qry(x,y); else{ for (i=1; i<=cnt; i++) for (j=i; j<=cnt; j++) if (l[i]<=x && x<=r[j]){ sum[i][j][a[x]]--; if (!sum[i][j][a[x]]) val[i][j]--; } if (!f[y]) f[y]=++tot; a[x]=f[y]; for (i=1; i<=cnt; i++) for (j=i; j<=cnt; j++) if (l[i]<=x && x<=r[j]){ if (!sum[i][j][a[x]]) val[i][j]++; sum[i][j][a[x]]++; } } } return 0; }
by lych
2016.2 5
相关文章推荐
- Java 集合类
- int 转换成 CString(VC2008里有这个问题)
- POJ3694 Network(边双连通+LCA)
- pycharm 常用设置
- mysql_real_escape_string总是返回false
- 爬虫基本知识
- JavaScript的this分别代表什么
- 用户爬虫例子
- 开源爬虫
- 终于懂了:Delphi消息的Result完全是生造出来的,不是Windows消息自带的(Delphi对Windows编程体系的改造越大,学习收获就越大)
- 【HDOJ】3686 Traffic Real Time Query System
- HDU——1019Least Common Multiple(多个数的最小公倍数)
- Yaf安装及配置
- java中形参长度可变的方法
- 多态
- 大话设计模式之初印象
- 【机房重构】——七层登陆代码分析
- INTERIGHT 京东自营旗舰店-京东 要把凡客给弄残啊这是。。
- 数据结构--动态规划
- [N皇后 构造] BZOJ 3101 N皇后