luoguP3960 [noip2017]列队(树状数组)

www.cnblogs.com/shaokele/


luoguP3960 [noip2017]列队

  Time Limit: 2 Sec
  Memory Limit: 512 MB

Description

  Sylvia 是一个热爱学习的女♂孩子。
  
  前段时间,Sylvia 参加了学校的军训。众所周知,军训的时候需要站方阵。
  
  Sylvia 所在的方阵中有 \(n \times m\) 名学生,方阵的行数为 \(n\) ,列数为 \(m\) 。
  
  为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中 的学生从 1 到 \(n \times m\) 编上了号码(参见后面的样例)。即:初始时,第 \(i\) 行第 \(j\) 列 的学生的编号是 \((i-1)\times m + j\) 。
  
  然而在练习方阵的时候,经常会有学生因为各种各样的事情需要离队。在一天 中,一共发生了 \(q\) 件这样的离队事件。每一次离队事件可以用数对 \((x,y) (1 \le x \le n, 1 \le y \le m)\) 描述,表示第 \(x\) 行第 \(y\) 列的学生离队。
  
  在有学生离队后,队伍中出现了一个空位。为了队伍的整齐,教官会依次下达 这样的两条指令:
  
  向左看齐。这时第一列保持不动,所有学生向左填补空缺。不难发现在这条 指令之后,空位在第 \(x\) 行第 \(m\) 列。
  
  向前看齐。这时第一行保持不动,所有学生向前填补空缺。不难发现在这条 指令之后,空位在第 \(n\) 行第 \(m\) 列。
  
  教官规定不能有两个或更多学生同时离队。即在前一个离队的学生归队之后, 下一个学生才能离队。因此在每一个离队的学生要归队时,队伍中有且仅有第 \(n\) 行 第 \(m\) 列一个空位,这时这个学生会自然地填补到这个位置。
  
  因为站方阵真的很无聊,所以 Sylvia 想要计算每一次离队事件中,离队的同学 的编号是多少。
  
  注意:每一个同学的编号不会随着离队事件的发生而改变,在发生离队事件后 方阵中同学的编号可能是乱序的。
 

Input

  输入共 \(q+1\) 行。
  
  第 1 行包含 3 个用空格分隔的正整数 \(n, m, q\) ,表示方阵大小是 \(n\) 行 \(m\) 列,一共发 生了 \(q\) 次事件。
  
  接下来 \(q\) 行按照事件发生顺序描述了 \(q\) 件事件。每一行是两个整数 \(x, y\) ,用一个空 格分隔,表示这个离队事件中离队的学生当时排在第 \(x\) 行第 \(y\) 列。
 

Output

  按照事件输入的顺序,每一个事件输出一行一个整数,表示这个离队事件中离队学 生的编号。
 

Sample Input

  2 2 3
  
  1 1
  
  2 2
  
  1 2
 

Sample Output

  1
  
  1
  
  4
  

HINT

  【输入输出样例 1 说明】
  
  列队的过程如上图所示,每一行描述了一个事件。 在第一个事件中,编号为 11 的同学离队,这时空位在第一行第一列。接着所有同学 向左标齐,这时编号为 2 2 的同学向左移动一步,空位移动到第一行第二列。然后所有同 学向上标齐,这时编号为 4 4 的同学向上一步,这时空位移动到第二行第二列。最后编号 为 11 的同学返回填补到空位中。
  
  【数据规模与约定】
  
  数据保证每一个事件满足 \(1 \le x \le n,1 \le y \le m\)
  

题目地址:  luoguP3960 [noip2017]列队

题目大意:

  一个 \(n*m\) 的队列,第 \(i*j\) 行的数编号为 \((i-1)*m+j\)
  每次取出 \(x\) 行 \(y\) 列的数,把它从队列中删去。
  把它右边的数都往左移
  把最后一列的数都向上移
  在把结果插入第 \(n\) 行 \(m\) 列
  重复上述过程
  

题解:

  先贴代码,以后填坑
  



AC代码

#include <cstdio>
#include <vector>
#include <algorithm>
#define ll long long
using namespace std;
const int N=300005;
int n,m,Q,len;
int X[N],Y[N],sol[N];
int T[N+N];
ll Num[N+N];
vector<ll> a[N];
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct node{
    int x,y,id;
}A[N];
bool cmp(node a,node b){
    if(a.x!=b.x)return a.x<b.x;
    return a.id<b.id;
}
void modify(int k,int tot){
    for(int i=k;i<=len;i+=i&(-i))
        T[i]+=tot;
}
int query(int k){
    int res=0;
    for(int i=k;i;i-=i&(-i))
        res+=T[i];
    return res;
}
int search(int tot){
    int l=1,r=len,res=-1;
    while(l<=r){
        int mid=(l+r)>>1;
        if(query(mid)>=tot){
            res=mid;
            r=mid-1;
        }else l=mid+1;
    }
    return res;
}
int main(){
    n=read();m=read();Q=read();
    len=max(n,m)+Q;
    for(int i=1;i<=Q;i++){
        A[i].x=X[i]=read();
        A[i].y=Y[i]=read();
        A[i].id=i;
    }
    sort(A+1,A+Q+1,cmp);
    for(int i=1;i<=len;i++)modify(i,1);
    int pre=1;
    for(int i=2;i<=Q+1;i++)
        if(A[i].x!=A[i-1].x){
            for(int j=pre;j<i;j++)
                if(A[j].y<m){
                    sol[A[j].id]=search(A[j].y);
                    modify(sol[A[j].id],-1);
                }
            for(int j=pre;j<i;j++)
                if(A[j].y<m)
                    modify(sol[A[j].id],1);
            pre=i;
        }
    for(int i=1;i<=Q;i++){
        ll ans;
        int k=search(X[i]);
        if(k<=n)ans=(ll)k*m;
        else ans=Num[k-n];
        modify(k,-1);
        if(Y[i]<m){
            a[X[i]].push_back(ans);
            if(sol[i]<m)ans=(ll)(X[i]-1)*m+sol[i];
            else ans=a[X[i]][sol[i]-m];
        }
        Num[i]=ans;
        printf("%lld\n",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/shaokele/p/9179428.html

时间: 2024-08-30 17:15:06

luoguP3960 [noip2017]列队(树状数组)的相关文章

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include

(POJ 3067) Japan (慢慢熟悉的树状数组)

Japan Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 29295   Accepted: 7902 Description Japan plans to welcome the ACM ICPC World Finals and a lot of roads must be built for the venue. Japan is tall island with N cities on the East coas

【二维树状数组】See you~

https://www.bnuoj.com/v3/contest_show.php?cid=9148#problem/F [题意] 给定一个矩阵,每个格子的初始值为1.现在可以对矩阵有四种操作: A x y n1 :给格点(x,y)的值加n1 D x y n1: 给格点(x,y)的值减n1,如果现在格点的值不够n1,把格点置0 M x1 y1 x2 y2:(x1,y1)移动给(x2,y2)n1个 S x1 y1 x2 y2 查询子矩阵的和 [思路] 当然是二维树状数组 但是一定要注意:lowbi

Vijos P1066 弱弱的战壕【多解,线段树,暴力,树状数组】

弱弱的战壕 描述 永恒和mx正在玩一个即时战略游戏,名字嘛~~~~~~恕本人记性不好,忘了-_-b. mx在他的基地附近建立了n个战壕,每个战壕都是一个独立的作战单位,射程可以达到无限(“mx不赢定了?!?”永恒[email protected][email protected]). 但是,战壕有一个弱点,就是只能攻击它的左下方,说白了就是横纵坐标都不大于它的点(mx:“我的战壕为什么这么菜”ToT).这样,永恒就可以从别的地方进攻摧毁战壕,从而消灭mx的部队. 战壕都有一个保护范围,同它的攻击

CF 313 DIV2 B 树状数组

http://codeforces.com/contest/313/problem/B 题目大意 给一个区间,问你这个区间里面有几个连续相同的字符. 思路: 表示个人用树状数组来写的...了解了树状数组的本质就行了. 当然用sum[r]-sum[l]也是可以的

Hdu5032 极角排序+树状数组

题目链接 思路:参考了题解.对询问进行极角排序,然后用树状数组维护一下前缀和即可. /* ID: onlyazh1 LANG: C++ TASK: test */ #include<bits/stdc++.h> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 typedef long long ll; const int maxn=1010; const int maxm=10

Curious Robin Hood(树状数组+线段树)

1112 - Curious Robin Hood    PDF (English) Statistics Forum Time Limit: 1 second(s) Memory Limit: 64 MB Robin Hood likes to loot rich people since he helps the poor people with this money. Instead of keeping all the money together he does another tri

【初识——树状数组】 区间求最值

说树状数组其实是一个索引表,但是是一个特殊的,树状的索引表,它利用了二进制的一些特性. 就区间求和的要求来说: 首先我们用a[]数组来存储原始数据.然后在a[]之上构造c[]数组来作为树状数组. 如图 这个图表示,当i为奇数时,c[i]中保存的都是a[i]本身.然后,c[2]中保存了a[1], a[2],共2个,c[4]中保存的是a[1], a[2], a[3], a[4],c[6]又是保存两个,c[5]和c[6].c[8]保存8个,c[1], c[2], c[3], c[4], c[5], c

树状数组求区间最大值

------  一直用 线段树 求区间最大值,想换种思路,用树状数组试试,肯定是可以的. 首先要对 树状数组的每个 i 所管理的区间有一定的理解.详见上篇博客: 树状数组(BIT)