信息推送(单点更新,求前缀和)

99封情书 提交于 2020-01-28 17:05:16

https://codeforces.com/contest/1288/problem/E

题意:n条信息,刚开始顺序为1-n,m次操作,每一次操作将某条信息置顶,其他信息后移

问每一条信息距离顶部最小距离和最大距离。

解法:扩大区间长度为n+m,利用树状数组进行单点更新和求前缀和,另用一个数组记录每一个点位置。

//#include <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <string>
#include <stdio.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <string.h>
#include <vector>
#define ME(x , y) memset(x , y , sizeof(x))
#define SF(n) scanf("%d" , &n)
#define rep(i , n) for(int i = 0 ; i < n ; i ++)
#define INF  0x3f3f3f3f
#define mod 1000000007
#define PI acos(-1)
using namespace std;
typedef long long ll ;
int c[600009];
int ma[300009] , mi[300009];
int l ;
int ans[300009];

int lowerbit(int x)
{
    return x&(-x);
}

void add(int x , int val)
{
    for(int i = x ; i <= l ; i += lowerbit(i))
    {
        c[i] += val ;
    }
}

int getsum(int x)
{
    int ans = 0 ;
    for(int i = x ; i >= 1 ; i -= lowerbit(i))
    {
        ans += c[i];
    }
    return ans ;
}

int main()
{
    int n , m ;
    scanf("%d%d" , &n , &m);
    l = n + m ;
    for(int i = 1 ; i <= n ; i++)
    {
        ans[i] = i + m;
        mi[i] = ma[i] = i ;
        add(i+m , 1);
    }
    for(int i = 0 ; i < m ; i++)
    {
        int x ;
        scanf("%d" , &x);
        mi[x] = 1;
        ma[x] = max(ma[x] , getsum(ans[x]));//每一次移动前查询此时距离。
        add(ans[x] , -1);
        ans[x] = m - i ;//更新位置
        add(ans[x] , 1);
    }
    for(int i = 1 ; i <= n ; i++)//可能存在没有置顶的信息,需要再筛查一遍
    {
        ma[i] = max(ma[i] , getsum(ans[i]));
    }
    for(int i = 1 ; i <= n ; i++)
    {
        cout << mi[i] << " " << ma[i] << endl ;
    }

    return 0 ;
}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!