J.Different Integers

题意就是给你l,r,问你在区间两侧的[1,l]和[r,n]中,不同数的个数。

两种思路:

1.将数组长度扩大两倍,for(int i=n+1;i<=2*n;i++) a[i]=a[i-n];就可以将两个分开的区间合并成一个区间[r,l+n],然后就可以通过主席树求解,套模板就可以了。

但是用主席树有风险,容易写超时,超内存,只能通过50%,初始化数组memset少写一个就过了,而且while(scanf("%d%d",&n,&m)==2)要写成这样,我赛后试了一下while(~scanf("%d%d",&n,&m)),过不了,只能过50%,所以主席树正好卡过去。

代码:

  1. //J-主席树刚好卡过
  2. #include<iostream>
  3. #include<cstdio>
  4. #include<cstring>
  5. #include<vector>
  6. #include<algorithm>
  7. #include<cmath>
  8. #include<cstdlib>
  9. #include<queue>
  10. using namespace std;
  11. const int maxn=*1e5+;
  12.  
  13. struct Node
  14. {
  15. int l,r,sum;
  16.  
  17. }p[maxn*];
  18. int la[maxn],a[maxn],root[maxn];
  19. int n,q,cnt;
  20.  
  21. int build(int l,int r)
  22. {
  23. int nc=++cnt;
  24. p[nc].sum=;
  25. p[nc].l=p[nc].r=;
  26. if(l==r){
  27. return nc;
  28. }
  29.  
  30. int m=l+r>>;
  31. p[nc].l=build(l,m);
  32. p[nc].r=build(m+,r);
  33. return nc;
  34. }
  35. int update(int pos,int c,int v,int l,int r)
  36. {
  37. int nc=++cnt;
  38. p[nc]=p[c];
  39. p[nc].sum+=v;
  40. if(l==r){
  41. return nc;
  42. }
  43.  
  44. int m=l+r>>;
  45. if(m>=pos)
  46. p[nc].l=update(pos,p[c].l,v,l,m);
  47. else
  48. p[nc].r=update(pos,p[c].r,v,m+,r);
  49. return nc;
  50. }
  51. int query(int pos,int c,int l,int r)
  52. {
  53. if(l==r) return p[c].sum;
  54. int m=l+r>>;
  55. if(m>=pos)
  56. return p[p[c].r].sum + query(pos,p[c].l,l,m);
  57. else
  58. return query(pos,p[c].r,m+,r);
  59. }
  60. int main()
  61. {
  62. while(scanf("%d%d",&n,&q)==){
  63. memset(la,-,sizeof(la));
  64. cnt=;
  65. for (int i=;i<=n;i++){
  66. scanf("%d",a+i);
  67. }
  68. for(int i=n+;i<=*n;i++)
  69. a[i]=a[i-n];
  70. n=n*;
  71. root[]=build(,n);
  72. for (int i=;i<=n;i++){
  73. int v=a[i];
  74. if(la[v]==-)
  75. root[i]=update(i,root[i-],,,n);
  76. else{
  77. int t=update(la[v],root[i-],-,,n);
  78. root[i]=update(i,t,,,n);
  79. }
  80. la[v]=i;
  81. }
  82. while(q--){
  83. int x,y;
  84. scanf("%d%d",&x,&y);
  85. printf("%d\n",query(y,root[n/+x],,n));
  86. }
  87. }
  88. }

2.叉姐官方题解思路是树状数组,离线按照 r 从小到大处理询问,考虑没出现的数字个数,假设 r = last[x],那么当 l < first[x] 时,x 没出现,用树状数组维护即可。

唉,真的是长的帅又厉害代码写的还优美,代码写的真的是好看,羡慕(✧◡✧)

代码:(叉姐代码)

  1. #include <bits/stdc++.h>
  2.  
  3. struct Query
  4. {
  5. int l, r, id;
  6. };
  7.  
  8. bool operator < (const Query& u, const Query& v)
  9. {
  10. return u.r < v.r;
  11. }
  12.  
  13. int main()
  14. {
  15. int n, q;
  16. while (scanf("%d%d", &n, &q) == ) {
  17. std::vector<int> a(n), first(n, -), last(n);
  18. int total = ;
  19. for (int i = ; i < n; ++ i) {
  20. scanf("%d", &a[i]);
  21. a[i] --, last[a[i]] = i;
  22. if (first[a[i]] == -) {
  23. total ++, first[a[i]] = i;
  24. }
  25. }
  26. std::vector<Query> queries;
  27. for (int i = , l, r; i < q; ++ i) {
  28. scanf("%d%d", &l, &r);
  29. queries.push_back(Query {l - , r - , i});
  30. }
  31. std::sort(queries.begin(), queries.end());
  32. std::vector<int> count(n), result(q);
  33. for (int i = , k = ; i < n; ++ i) {
  34. while (k < q && queries[k].r == i) {
  35. int& ref = result[queries[k].id] = total;
  36. for (int j = queries[k].l; j < n; j += ~j & j + ) {
  37. ref -= count[j];
  38. }
  39. k ++;
  40. }
  41. if (last[a[i]] == i) {
  42. for (int j = first[a[i]] - ; ~j; j -= ~j & j + ) {
  43. count[j] ++;
  44. }
  45. }
  46. }
  47. for (int i = ; i < q; ++ i) {
  48. printf("%d\n", result[i]);
  49. }
  50. }
  51. }

自己改了一下叉姐代码加了一点注释的代码:

  1. //J-离线树状数组处理
  2. #include<iostream>
  3. #include<cstdio>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<queue>
  8. #include<map>
  9. #include<vector>
  10. using namespace std;
  11. const int maxn=1e5+;
  12. const int inf=0x3f3f3f3f;
  13. const double eps=1e-;
  14. struct node
  15. {
  16. int l,r,id;
  17. bool operator< (const node &a) const{ //结构体内嵌比较函数
  18. return r<a.r;
  19. }
  20. };
  21. int main()
  22. {
  23. int n,q;
  24. while(~scanf("%d%d",&n,&q)){
  25. vector<int>a(n),first(n, -),last(n);
  26. int total=;
  27. for (int i=;i<n;i++){
  28. scanf("%d",&a[i]);
  29. a[i]--,last[a[i]]=i;//记录元素最后出现的位置
  30. if(first[a[i]]==-){//如果元素之前未出现,则记录第一次出现的位置
  31. total++;
  32. first[a[i]]=i;
  33. }
  34. }
  35. vector<node> queries;
  36. for (int i=;i<q;i++) {
  37. int l,r;
  38. scanf("%d%d",&l,&r);
  39. queries.push_back(node {l-,r-,i});//将区间和id存到容器内
  40. }
  41. sort(queries.begin(),queries.end());//区间右边界升序排序(结构体内内嵌了比较函数)
  42. vector<int>count(n),result(q);
  43. for (int i=,k=;i<n;i++){//树状数组维护
  44. while(k<q&&queries[k].r==i){
  45. int &ref=result[queries[k].id]=total;
  46. for(int j=queries[k].l;j<n;j+=~j&j+){//~j&j+1 +的优先级比&高
  47. ref-=count[j];
  48. }
  49. k++;
  50. }
  51. if(last[a[i]]==i){
  52. for(int j=first[a[i]]-;~j;j-=~j&j+){
  53. count[j]++;//统计没有出现过的元素个数
  54. }
  55. }
  56. }
  57. for (int i=;i<q;i++) {
  58. printf("%d\n",result[i]);
  59. }
  60. }
  61. }

讲道理,我是真的菜,难受。

牛客网 暑期ACM多校训练营(第一场)J.Different Integers-区间两侧不同数字的个数-离线树状数组 or 可持久化线段树(主席树)的更多相关文章

  1. 牛客网暑期ACM多校训练营 第九场

    HPrefix Sum study from : https://blog.csdn.net/mitsuha_/article/details/81774727 k较小.分离x和k. 另外的可能:求a ...

  2. 牛客网暑期ACM多校训练营(第四场):A Ternary String(欧拉降幂)

    链接:牛客网暑期ACM多校训练营(第四场):A Ternary String 题意:给出一段数列 s,只包含 0.1.2 三种数.每秒在每个 2 后面会插入一个 1 ,每个 1 后面会插入一个 0,之 ...

  3. 牛客网暑期ACM多校训练营(第五场):F - take

    链接:牛客网暑期ACM多校训练营(第五场):F - take 题意: Kanade有n个盒子,第i个盒子有p [i]概率有一个d [i]大小的钻石. 起初,Kanade有一颗0号钻石.她将从第1到第n ...

  4. 牛客网 暑期ACM多校训练营(第二场)A.run-动态规划 or 递推?

    牛客网暑期ACM多校训练营(第二场) 水博客. A.run 题意就是一个人一秒可以走1步或者跑K步,不能连续跑2秒,他从0开始移动,移动到[L,R]的某一点就可以结束.问一共有多少种移动的方式. 个人 ...

  5. 牛客网 暑期ACM多校训练营(第一场)A.Monotonic Matrix-矩阵转化为格子路径的非降路径计数,Lindström-Gessel-Viennot引理-组合数学

    牛客网暑期ACM多校训练营(第一场) A.Monotonic Matrix 这个题就是给你一个n*m的矩阵,往里面填{0,1,2}这三种数,要求是Ai,j⩽Ai+1,j,Ai,j⩽Ai,j+1 ,问你 ...

  6. 牛客网暑期ACM多校训练营(第三场)H Diff-prime Pairs (贡献)

    牛客网暑期ACM多校训练营(第三场)H Diff-prime Pairs (贡献) 链接:https://ac.nowcoder.com/acm/contest/141/H来源:牛客网 Eddy ha ...

  7. 2018牛客网暑期ACM多校训练营(第二场)I- car ( 思维)

    2018牛客网暑期ACM多校训练营(第二场)I- car 链接:https://ac.nowcoder.com/acm/contest/140/I来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 ...

  8. 牛客网 暑期ACM多校训练营(第二场)J.farm-STL(vector)+二维树状数组区间更新、单点查询 or 大暴力?

    开心.jpg J.farm 先解释一下题意,题意就是一个n*m的矩形区域,每个点代表一个植物,然后不同的植物对应不同的适合的肥料k,如果植物被撒上不适合的肥料就会死掉.然后题目将每个点适合的肥料种类( ...

  9. 牛客网暑期ACM多校训练营(第七场)Bit Compression

    链接:https://www.nowcoder.com/acm/contest/145/C 来源:牛客网 题目描述 A binary string s of length N = 2n is give ...

  10. 牛客网暑期ACM多校训练营(第一场) - J Different Integers(线段数组or莫队)

    链接:https://www.nowcoder.com/acm/contest/139/J来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 524288K,其他语言1048 ...

随机推荐

  1. vue计算属性和观察者

    1. 计算属性 模板内的表达式非常便利,但在模板中放入太多的逻辑会让模板过重且难以维护,所有就有了计算属性 例子: //html代码 <div id="example"> ...

  2. shell编程——参数传递

    1.Linux Shell参数引用 $0 这个程式的执行名字$n 这个程式的第n个参数值,n=1..9$* 这个程式的所有参数$# 这个程式的参数个数$$ 这个程式的PID$! 执行上一个背景指令的P ...

  3. Spring 各种注解备注

    Spring 各种注解备注 felix_feng 关注 2016.12.28 10:34* 字数 2092 阅读 790评论 0喜欢 6 转载 (http://blog.csdn.net/sudilu ...

  4. 修改window 10 开始菜单问题

    cmd->powershell Get-AppxPackage | % { Add-AppxPackage -DisableDevelopmentMode -Register "$($ ...

  5. 《Cracking the Coding Interview》——第1章:数组和字符串——题目5

    2014-03-18 01:40 题目:对字符串进行类似游程编码的压缩,如果压缩完了长度更长,则返回不压缩的结果.比如:aabcccccaaa->a2b1c5a3,abc->abc. 解法 ...

  6. 《Cracking the Coding Interview》——第1章:数组和字符串——题目2

    2014-03-18 01:30 题目:反转一个char *型的C/C++字符串. 解法:一头一尾俩iterator,向中间靠拢并且交换字符. 代码: // 1.2 Implement a funct ...

  7. 《算法》C++代码 Floyd

    今天写写最短路径的Floyd算法(有翻译叫弗洛伊德,不过这奇葩翻译用来读读就好……). 这个算法的实质,广义来讲,其实是DP(动态规划).其实按说,算法应该先说说什么贪心.搜索.DP.二分之类的基本算 ...

  8. U盘的容量变小了怎么办?

    之前买了个U盘,后来给朋友装系统弄成U盘启动盘了,就发现U盘容量变少了几百兆,原来是因为做U盘启动盘的时候,U盘启动盘制作软件都是把写入U盘的PE文件隐藏了,防止用户不小心删除文件. 所以说这些空间应 ...

  9. python的inspect模块

    一.type and members 1. inspect.getmembers(object[, predicate]) 第二个参数通常可以根据需要调用如下16个方法: 返回值为object的所有成 ...

  10. Limeng:Individual Project: Word frequency program -BUAA Advanced Software Engineering

    11061190-李孟 Implement a console application to tally the frequency of words under a directory (2 mod ...