~~~题面~~~

题解:

  之前写的splay,,,然而一直没调出来,我感觉是某个细节想错了,,然而已经重构4次代码不想再写splay了。于是今天尝试了线段树的解法。

  首先因为每次出列之后的变化都是将当前行左移,然后将最后一列上移,所以最后一列不适合和其他的行放在一起处理。

  因此对于每行的前m - 1位开一棵线段树,对于最后一列开一棵线段树。

  但是因为空间开销过大无法承受,因此考虑动态开点。一开始每棵线段树内只有一个节点,这个节点代表了当前行1 ~ m - 1的所有节点。

  如果我们要从中删除一个节点,就跟普通线段树类似的向下遍历找到单点,然后修改权值为0,并且同步修改这条链上的节点数总和。跟普通线段树不同的是,动态开点需要在函数的最开头判断这个节点是否存在,如果不存在,就建出这个节点,并给这个节点加上一些基本的信息,然后继续向下遍历。

  如果我们要添加一个节点到树中,那么我们就直接加在这棵树所有已经存在的叶子节点的后面那个叶子节点处即可。即下图。(虚线表示省略的节点)

同时维护所有线段树即可,注意细节。

 #include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 301000
#define ac 8000000
#define LL long long
#define D printf("line in %d\n", __LINE__); int n, m, q, w, cnt, now;
int root[AC], tree[ac], ls[ac], rs[ac], pos[ac];
LL id[ac], go;//id[ac]要开ac啊,,,,
//对于
inline int read()
{
int x = ;char c = getchar();
while(c > '' || c < '') c = getchar();
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x;
} inline int cal(int l, int r)
{
if(now <= n)
{
if(r <= m - ) return r - l + ;
else if(l <= m - ) return (m - ) - l + ;
else return ;
}
else
{
if(r <= n) return r - l + ;
else if(l <= n) return n - l + ;
else return ;
}
} void kth(int &x, int l, int r)//当前节点,当前区间
{
if(!x) x = ++ cnt, tree[x] = cal(l, r);//第一次开出来自然是满的
if(l == r)
{
tree[x] = ;
if(!id[x]) go = (now <= n) ? (LL)(now - ) * (LL)m + l : (LL)m * (LL)l;//如果这个点没有被赋过值,那么就应该是原来的编号
else go = id[x]; //编号爆ll,,,
return ;
}
else
{
-- tree[x];//删除一个节点
int mid = (l + r) >> ;
int tmp = ls[x] ? tree[ls[x]] : cal(l, mid);//获取左边的节点个数
if(w <= tmp) kth(ls[x], l, mid);
else w -= tmp, kth(rs[x], mid + , r);
}
} void ins(int &x, int l, int r)
{
if(!x) x = ++ cnt, tree[x] = cal(l, r);
if(l == r) {tree[x] = , id[x] = go; return ;}
int mid = (l + r) >> ;
++ tree[x];//加入一个节点
if(w <= mid) ins(ls[x], l, mid);//因为已经钦定了位置
else ins(rs[x], mid + , r);//不然去右边
} void pre()
{
n = read(), m = read(), q = read();
for(R i = ; i <= n; i ++) root[i] = ++cnt, tree[cnt] = m - ;
root[n + ] = ++cnt, tree[cnt] = n;//给最后一列单独开一个
} void work()
{
int a, b;LL tmp;
for(R i = ; i <= q; i ++)
{
a = read(), b = read();
if(b < m)
{
now = a, w = b;
kth(root[now], , m + q);//对于维护行的线段树,边界应该是m + q吧
w = a, now = n + , tmp = go;//记录出来的人
printf("%lld\n", tmp);
kth(root[now], , n + q);//从最后一列中取人,
now = a, ++ pos[now], w = m - + pos[now];
ins(root[now], , m + q);
now = n + , ++ pos[now], w = n + pos[now], go = tmp;//把出来的人放在最后一列的最后一个
ins(root[now], , n + q);
}
else
{
now = n + , w = a;
kth(root[now], , n + q);
printf("%lld\n", go);
++ pos[now], w = n + pos[now];//直接算出来应该放在哪个位置
ins(root[now], , n + q);
}
}
} int main()
{
// freopen("in.in", "r", stdin);
pre();
work();
// fclose(stdin);
return ;
}

最新文章

  1. Android studio使用gradle动态构建APP(不同的包,不同的icon、label)
  2. VMware三种上网模型
  3. FTP安装与使用
  4. 翻译-使用Spring调用SOAP Web Service
  5. AES128和AES256主要区别和安全程度是多少?他们对于机器的消耗是怎样的?两者性能如何?实际开发如何选择?
  6. linux运维笔记——常用命令详解diff
  7. 如何避免测试人员提交重复的Bug
  8. js对select动态添加和删除OPTION
  9. Installing Python 3.5.2 from source
  10. xml结构
  11. bzoj 4010: [HNOI2015]菜肴制作 拓扑排序
  12. 整理Linux查看系统日志的一些经常使用命令
  13. windows+php5.5+apache2.4+tomcat+mod_jk配置
  14. 深入分析 Java I/O 的工作机制
  15. 08_Android中的SimpleAdapter的使用
  16. C# 高级编程01----.Net基础介绍
  17. C# socket实践 - 简易版FTP(Server &amp; Client)
  18. sql server中的用户临时表和全局临时表的区别
  19. [No0000193]Chrome浏览器控制台(console)花式调试
  20. Maven 的基本配置与使用

热门文章

  1. LINUX SSH 建立密钥对
  2. elasticsearch 5.x 系列之六 文档索引,更新,查询,删除流程
  3. vuls安装记录
  4. Python3乘法口诀表(由上至下+由下至上)
  5. mongodb常用命令学习笔记
  6. spring boot踩坑记
  7. lambda, 匿名函数, 变量,传参
  8. 在WPF中自定义控件(1)
  9. Phoenix映射HBase数据表
  10. Hive数据倾斜和解决办法