信息推送(单点更新,求前缀和)
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 ; }