NOIP2017 Day2 T3 列队(treap)

  可以直接用treap上大模拟...n+1个treap维护n行的前m-1个点和最后一列。

  需要支持删除一个点或者一段区间,而空间并不支持存下所有的点的时候,可以用一个点代替一个区间,记录区间首项的值和区间长度,这样每次查询某个点x的时候就可以用x在某个点y代表的区间里的rank来得到x的值,然后把x删去的时候,就把y这个区间从$[l,r]$拆分成$[l,x-1]$和$[x+1,r]$,重新加入。

  类似的题有NOI超级钢琴

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define ll long long
#define int long long
#define lt tree[x].ls
#define rt tree[x].rs
using namespace std;
const int maxn=6000010;
struct poi{ll beg; int rnd, size, ls, rs, len;}tree[maxn];
int n, m, Q, x, y, tott, tmp, rk;
ll ans;
int root[maxn], cnt[maxn], Len[maxn];
inline void read(int &k)
{
    int f=1; k=0; char c=getchar();
    while(c<‘0‘ || c>‘9‘) c==‘-‘ && (f=-1), c=getchar();
    while(c<=‘9‘ && c>=‘0‘) k=k*10+c-‘0‘, c=getchar();
    k*=f;
}
inline void build(int &x, ll beg, int len)
{
    tree[x=++tott].beg=beg; tree[x].size=1;
    tree[x].len=Len[x]=len;
    tree[x].rnd=rand()<<15|rand();
}
inline void up(int x)
{
    tree[x].size=tree[lt].size+tree[rt].size+1;
    tree[x].len=tree[lt].len+tree[rt].len+Len[x];
}
void split(int x, int &l, int &r, int k)
{
    if(!k) l=0, r=x;
    else if(tree[x].size==k) l=x, r=0;
    else if(tree[lt].size>=k) r=x, split(lt, l, lt, k), up(x);
    else l=x, split(rt, rt, r, k-tree[lt].size-1), up(x);
}
void rank(int x, int k)
{
    if(tree[lt].len<k && tree[lt].len+Len[x]>=k) ans=k-tree[lt].len, rk+=tree[lt].size+1;
    else if(k<=tree[lt].len) rank(lt, k);
    else rk+=tree[lt].size+1, rank(rt, k-tree[lt].len-Len[x]);
}
void merge(int &x, int l, int r)
{
    if(!l || !r) x=l+r;
    else if(tree[l].rnd<tree[r].rnd) x=l, merge(rt, rt, r), up(x);
    else x=r, merge(lt, l, lt), up(x);
}
inline void disc(int &Root, ll &poi, int pos)
{
    int x, y;
    rk=0; rank(Root, pos);
    split(Root, Root, y, rk); if(rk-1) split(Root, Root, x, rk-1); else x=Root;
    if(ans-1) build(tmp, tree[x].beg, ans-1), merge(Root, Root, tmp);
    if(Len[x]-ans) build(tmp, tree[x].beg+ans*(Root==root[n+1]?m:1), Len[x]-ans), merge(Root, Root, tmp);
    merge(Root, Root, y); poi=x;
}
inline ll query(int posx, int posy)
{
    if(posy!=m)
    {
        ll ANS, poi;
        disc(root[posx], poi, posy); ANS=tree[poi].beg+ans-1;
        build(tmp, ANS, 1); merge(root[n+1], root[n+1], tmp);
        disc(root[n+1], poi, posx); poi=tree[poi].beg+(ans-1)*m;
        build(tmp, poi, 1); merge(root[posx], root[posx], tmp);
        return ANS;
    }
    ll poi;
    disc(root[n+1], poi, posx); poi=tree[poi].beg+(ans-1)*m;
    build(tmp, poi, 1); merge(root[n+1], root[n+1], tmp);
    return poi;
}
#undef int
int main()
{
    srand(19260817);
    read(n); read(m); read(Q);
    for(int i=1;i<=n;i++) build(root[i], 1ll*1+(i-1)*m, m-1); build(root[n+1], m, n);
    for(int i=1;i<=Q;i++) read(x), read(y), printf("%lld\n", query(x, y));
}

时间: 2024-08-02 02:55:45

NOIP2017 Day2 T3 列队(treap)的相关文章

NOIP2017D2T3 列队—Treap

NOIP2017列队 Description Sylvia 是一个热爱学习的女孩子.  前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia所在的方阵中有n × m名学生,方阵的行数为 n,列数为m.  为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中的学生从 1 到 n × m 编上了号码(参见后面的样例).即:初始时,第 i 行第 j 列的学生的编号是(i−1)×m+j.  然而在练习方阵的时候,经常会有学生因为各种各样的事情需要离队.

【NOIP之旅】NOIP2014 day2 T3 解方程

3.解方程 (equation.cpp/c/pas) [问题描述] 已知多项式方程: 求这个方程在[1, m]内的整数解(n和m均为正整数).   [输入] 输入文件名为equation.in. 输入共n+2行. 第一行包含2个整数n.m,每两个整数之间用一个空格隔开. 接下来的n+1行每行包含一个整数,依次为a0,a1,a2,……,an. [输出] 输出文件名为equation.out. 第一行输出方程在[1, m]内的整数解的个数. 接下来每行一个整数,按照从小到大的顺序依次输出方程在[1,

HNOI2016 Day2 T3 大数(BZOJ4542)

莫队算法 今天为了做这道题先去学了莫队算法,然后A掉了莫队算法的入门题目——小Z的袜子. 考场上面我傻逼的打了一个高精度,华丽丢掉暴力分.然而我发现只需要取个模就可以了,考场上傻了. 学完莫队算法之后,发现这道题其实就是一个裸题. 一开始依然是莫队算法的方式,按左端点所在块的编号为第一关键字,右端点编号为第二关键字排序, 考虑先暴力处理每个块的第一组询问,之后可以发现我们只需要微调一下区间的左右端点就可以了.比如说:我上次处理了1 5,那么1 6就可以只把6加进去就可以了:如果这一次是2 6,那

【GDOI 2011 DAY2 T3】零什么的最讨厌了 (快速求阶乘、中国剩余定理)

问题描述: 林记在做数学习题的时候,经常遇到这种情况:苦思冥想了很久终于把问题解出来,结果发现答案是0,久而久之林记在得到习题答案是0的时候就没有了做出一道难题的成就感.于是林记决定:以后出题,答案一定不能是0,例如求n!最低位非零数这样的习题就很不错了. 现在林记提出了一个更难一点的问题:求n!在K进制下的最低位非零数.其中K符合一些特殊的条件:K是由若干个互不相同的质数相乘得出来的,例如K=2,3,5,6,7,10…… 输入格式: 首先输入的第一行是一个整数Q,表示询问的个数. 接下来是Q个

2012Noip提高组Day2 T3 疫情控制

题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点.但特别要注意的是,首都是不能建立检查点的. 现在,在 H 国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队.一支军队可以在有道路连接的城市间移动

NOIP2017 Day1 T3 逛公园(最短路+拓扑排序+DP)

神tm比赛时多清个零就有60了T T 首先跑出1起点和n起点的最短路,因为k只有50,所以可以DP.设f[i][j]表示比最短路多走i的长度,到j的方案数. 我们发现如果在最短路上的和零边会有后向性,怎么办呢?拓扑排序. 把最短路上的点和零边的点拉出来跑拓扑排序,如果有零环的话必定度数不为0,而且要注意零环必须在<=最短路+k的路径上才输出-1,这个就用刚刚跑出来的1起点到n起点的最短路来判断就好了. 然后先按拓扑序DP出i相同的,然后再DP不在最短路上或者零边的. #include<iost

NOIP2017 Day2 T1 奶酪

题目描述 现有一块大奶酪,它的高度为 hhh ,它的长度和宽度我们可以认为是无限大的,奶酪 中间有许多 半径相同 的球形空洞.我们可以在这块奶酪中建立空间坐标系,在坐标系中, 奶酪的下表面为z=0z = 0z=0 ,奶酪的上表面为z=hz = hz=h . 现在,奶酪的下表面有一只小老鼠 Jerry,它知道奶酪中所有空洞的球心所在的坐 标.如果两个空洞相切或是相交,则 Jerry 可以从其中一个空洞跑到另一个空洞,特别 地,如果一个空洞与下表面相切或是相交,Jerry 则可以从奶酪下表面跑进空洞

NOIP2017小结

title: NOIP2017小结 tags: --- Day2 T3 题意十分的简洁,就是需要弄个数据结构去维护一个矩阵中,删除一个位置,然后把这一行左移一个单位,再把最后一列前移一个单位.反正,我一看就觉得是线段树,直接建\(n+1\)个线段树,就可以直接搞了,二看就觉得空间分分钟炸掉.于是就没啥办法了. \(30pts\) 考虑\(30pts\)的数据,暴力模拟就好了. \(50pts\) 然后还有一个\(20pts\)的数据,\(q\)比较小,似乎有一种\(q^2\)的做法,反正我是不会

[随笔]NOIP2017提高组复赛 游记

前言 真正意义上的第一篇游记,经历了第一次正式大考,希望自己能在这条道路上走得足够远... 当然最主要的梦想还是THU喔! Day -2 今天就是NOIP考前在机房呆的最后一天,上午打完了最后一场模拟赛,是NOIP模拟赛50,难以置信集训期间考了这么多场QAQ 应该这场就是信心赛了,因为好像上午要和我们联考的学校放了OD鸽子了2333(喜闻乐见) 然后蒟蒻的我信心赛只打了210分rank12 T-T,只能说RP++ 下午没有考试,于是机房内的气氛从原来的高级算法乱飞,变成了都在码最基础的模板 临