列队----树状数组

有趣等级:一般般(试问在理解了好久,写了好久,调了好久以后我还会觉得它有趣吗?!)

有趣理由:vector与树状数组配合极其默契


注意到有%30的数据x=1

这意味着所有的操作只涉及第一行以及最后一列

当第一行有人出队时,最后一列会补上,出队的人又会补上最后一列

考虑将第一行的人和最后一列的人压成一个序列,每次将第一行出队的人排到序列的最后,再将序列出队的人后面的人都往前挪,这也能完成状态的模拟,但是这样做时间复杂度不可接受。

复杂度的瓶颈在于将人往前挪,于是我们考虑优化这个东西。

初始给每一个位置都标为1,表示这个位置上有1个人。当一个人离开后,我们不让后面的人上来覆盖这个位置,而是将这个位置打上标记0,表示这个位置上没有人。当要第一行第y列的人出队时,考虑这个人原来是在哪一个位置上的。假设这个人原来在位置h上,现在它在第y列,这意味着它以及它前面有y个人,所以我们只要找到一个最小的位置使得这个位置以及这个位置之前有y个人,就可以得出h,然后计算出这个人的编号,将它位置标记为0并将它加到序列末尾。

由于0和1的标记,我们要找的其实就是最小的前缀和为y的位置。用树状数组来动态维护前缀和,又由于前缀和单调不递减,故可以用二分来查找这个位置。

当然原来的位置h可能大于m,这说明它是由第一行出队的人加到最后一列末尾的数,这部分可以用vector/数组维护

#include <bits/stdc++.h>
using namespace std;
int n,m,q,c[1000010];
long long b[1000010];
int N;
void Add(int x,int v)
{for (;x<=N;x+=x&(-x))c[x]+=v;
}
int Get(int x)
{int ans=0;for (;x;x-=x&(-x))ans+=c[x];return ans;
}
int main()
{N=n+m+q;for (int i=1;i<=m;i++)b[i]=i,Add(i,1);for (long long i=2;i<=n;i++)b[m+i-1]=i*m,Add(m+i-1,1);int nu=n+m-1; for (int i=1;i<=q;i++){int x,y;int id=0;scanf("%d%d",&x,&y);int l=1,r=nu;while (l+1<r){int mid=(l+r)>>1;if (Get(mid)>=y) r=mid;else l=mid+1;}if (Get(l)==y) id=l;else id=r;b[++nu]=b[id]; printf("%lld\n",b[id]);Add(id,-1);Add(nu,1);b[id]=0;}
}

%100数据

两行之间除最后一列外是不相互影响的

不妨将每一行看做只有1~m-1列,最后一列特殊处理

然后对于每一行的询问都按时间顺序单独预处理出这个人原来在这一行的位置h(注:这里只要求h,不要求h具体编号)

这可以排序,然后像上面%30的数据一样做到

再将询问按照时间排序,依次操作

这里对于每一行和最后一列分别维护一个vector,用来存储增进来的数

对于每个询问(x,y):

找出最后一列第x个数,并计算出它原来在最后一列的位置hh(第hh行)

如果hh<=n这个数的编号就是hh*m,否则就时v[0] [hh-n-1] (v[0]是列的vector,下标从0开始)

  • y<m:

    • h<m,直接计算编号。

    • h>=m,v[x] [h-m] (下标从0开始)

    • 然后将这个人(实际是编号)加入到最后1列的vector中,将hh加入到该 行的vector中。

  • y==m:

    • 编号就是hh
    • 将hh加入到最后1列的vector中

以上是大概操作,看似也解决了问题,但貌似还遗留了一个问题

如何求出最后一列的x个数??

注意到对于每一行(列1~m-1)询问第y个数(第y列)因为对于y的预处理我们得到了h,所以每次询问的h对于每一行来说是不会重复的,直接用就好了。

但是对于最后一列询问第x个数(第x行),这我们没有进行过预处理,x是会重复的,所以我们也要像%30的数据那样子维护出hh,所以一边做一边维护就好了

#include <bits/stdc++.h>
using namespace std;
int n,m,q,c[600010],INF=600000;
vector <long long> vec[300010];
struct dsa
{int x,y,id,gg;
}a[300010];
bool cmp(dsa p1,dsa p2)
{if (p1.x==p2.x) return p1.gg<p2.gg;return p1.x<p2.x;
}
bool cmp_(dsa p1,dsa p2)
{return p1.gg<p2.gg;
}
void Add(int x,int v)
{for (;x<=INF;x+=x&(-x))c[x]+=v;
}
int Find(int x)
{int ans=0;for (;x;x-=x&(-x))ans+=c[x];return ans;
}
int main()
{freopen("phalanx.in","r",stdin);freopen("phalanx.out","w",stdout);scanf("%d%d%d",&n,&m,&q);for (int i=1;i<=q;i++)scanf("%d%d",&a[i].x,&a[i].y),a[i].gg=i;sort(a+1,a+q+1,cmp);int L=1;for (int i=1;i<m;i++)Add(i,1);for (int i=1;i<=n;i++){int nu=m-1;if (L>q) break; if (a[L].x!=i) continue;int R=L;while (a[R+1].x==i) R++;for (int j=L;j<=R;j++){if (a[j].y==m) continue;int l=1,r=nu;while (l+1<r){int mid=(l+r)>>1;if (Find(mid)>=a[j].y) r=mid;else l=mid+1;}if (Find(l)==a[j].y) a[j].id=l;else a[j].id=r;Add(a[j].id,-1);Add(++nu,1);}for (int j=L;j<=R;j++){if (a[j].y==m) continue;Add(a[j].id,1);Add(nu--,-1);}L=R+1;}sort(a+1,a+q+1,cmp_);for (int i=1;i<m;i++)Add(i,-1);for (int i=1;i<=n;i++)Add(i,1);int N=n;for (int i=1;i<=q;i++){         int l=1,r=N;long long num=0;while (l+1<r){int mid=(l+r)>>1;if (Find(mid)>=a[i].x) r=mid;else l=mid+1;}int h=0;if (Find(l)==a[i].x) h=l;else h=r;if (a[i].y<m) {       if (a[i].id>=m){num=vec[a[i].x][a[i].id-m];vec[a[i].x][a[i].id-m]=0;}else num=(a[i].x-1)*1LL*m+a[i].id; if (h<=n) vec[a[i].x].push_back(h*1LL*m);else vec[a[i].x].push_back(vec[0][h-n-1]),vec[0][h-n-1]=0;Add(h,-1);Add(++N,1);vec[0].push_back(num);}else if (a[i].y==m){if (h>n) num=vec[0][h-n-1],vec[0][h-n-1]=0;else num=h*1LL*m;Add(h,-1);vec[0].push_back(num);Add(++N,1); }printf("%lld\n",num);}return 0;
}

然后发现树状数组并不比动态开点线段树好搞,luogu上有些代码跑的飞快,不知有什么妙招,树状数组还是稳的,时限2s,树状数组跑不到1s。
我为什么要写树状数组呢,因为我考试的时候想到了%30x=1的做法,就想着,不如续下去吧
事实证明还没续完我就要续命了。。。

为什么树状数组跑的比动态开点线段树满啊

【noip2017T3】列队----树状数组相关推荐

  1. 洛谷 P5057 [CQOI2006]简单题(树状数组)

    嗯... 题目链接:https://www.luogu.org/problem/P5057 首先发现这道题中只有0和1,所以肯定与二进制有关.然后发现这道题需要支持区间更改和单点查询操作,所以首先想到 ...

  2. Color the ball(HDU1556)树状数组

    每次对区间内气球进行一次染色,求n次操作后后所有气球染色次数. 树状数组,上下区间更新都可以,差别不大. 1.对于[x,y]区间,对第x-1位减1,第y位加1,之后向上统计 #include<b ...

  3. 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组

    [BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...

  4. Codeforces 629D Babaei and Birthday Cake(树状数组优化dp)

    题意: 线段树做法 分析: 因为每次都是在当前位置的前缀区间查询最大值,所以可以直接用树状数组优化.比线段树快了12ms~ 代码: #include<cstdio> #include< ...

  5. poj_3067 树状数组

    题目大意 左右两个竖排,左边竖排有N个点,从上到下依次标记为1,2,...N; 右边竖排有M个点,从上到下依次标记为1,2....M.现在从K条直线分别连接左边一个点和右边一个点,求这K条直线的交点个 ...

  6. hdu 1166 敌兵布阵(树状数组)

    题意:区间和 思路:树状数组 #include<iostream> #include<stdio.h> #include<string.h> using names ...

  7. Equalizing Two Strings 冒泡排序or树状数组

    首先考虑排序后相等 如果排序后相等的话就只考虑reverse长度为2的,所以a或者b排序后存在相邻两个字母相等的话就puts YES,n>26也直接puts YES 不然的话就假设c为a,b排完 ...

  8. Hdu 6534 Chika and Friendly Pairs 莫队算法+树状数组

    题目链接 题意求给区间[L,R]中有少对(i,j)满足i<j且abs(a[i]-a[j])<=k. 首先来说暴力的方法就是离散化,然后用树状数组来维护,但是m次询问,m很大,所以说一定会t ...

  9. HDU - 5877 Weak Pair 2016 ACM/ICPC 大连网络赛 J题 dfs+树状数组+离散化

    题目链接 You are given a rootedrooted tree of NN nodes, labeled from 1 to NN. To the iith node a non-neg ...

最新文章

  1. arraylist 后往前遍历_面试官:谈谈常用的Arraylist和Linkedlist的区别
  2. AI如何落地企业?UCloud三步走战略:Build,Train,Deploy
  3. ML之API:国内外各大人工智能平台(百度云/华为云/阿里云/Face++等)及其API的简介、使用方法之详细攻略
  4. RSA加密的填充模式
  5. Python:常用模块简介(1)
  6. CSS3实现Loading动画特效
  7. ios 支付验证 php,PHP验证IOS原生支付是否成功(代码全篇)
  8. 给定字符串,实现大小写之间的转换
  9. [转]深入理解Java之线程池
  10. python异步请求aiohttp_利用aiohttp制作异步爬虫
  11. 面试题:Elasticsearch和solr的区别
  12. 看看中国科技巨头们在智能音箱行业的竞争
  13. 广西艺术学院2012年本科招生专业考试通知
  14. 关于数据仓库中变化历史数据处理方式:全量表、快照表、拉链表
  15. LaTex 自动生成IEEE格式的参考文献
  16. PacBio三代宏基因组测序大幅提升海洋水体宏基因组研究效果
  17. 稀疏数组的创建与读写文件操作
  18. php twig中文手册,使用技巧 · Twig 中文文档 · 看云
  19. SC系列(SC-20S)低频率小型SMD石英晶振SC-20S 32.768KHZ 12.5PF/20PPM
  20. js实现排行榜(根据我微信小程序项目所分享)完整版

热门文章

  1. 计算机二级设置用户名,计算机二级ms office考试设置技巧
  2. 深度学习AdaGrad算法
  3. 如何将pdf图片文字转换成word 文字word图片怎么转换pdf
  4. Linux中的小型数据库 SQLite3
  5. 11g Grid Control安装过程的一些“坑”
  6. centOS7虚拟机设置固定IP
  7. MySQL中导入CSV文件数据
  8. 图片怎么批量抠图?这几种方法都可以实现批量抠图
  9. jquery实现控制div显示跟隐藏办法。
  10. jQuery隐藏/显示