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 ;
}
原文:https://www.cnblogs.com/nonames/p/12238312.html