题意:一个序列p,所有的逆序对间直接存在一条边,现在将这些点染色,相邻的点颜色不能相同,问最少用多少种颜色,并输出每个点的颜色
解析:不难想到的是,最少的颜色种类为最长单调递减序列的长度,现在考虑每个点染什么颜色的问题,假设第i个点染得颜色为x,那么i节点之前至少存在一个已i节点结尾的最长单调递减序列,长度为x,因为单调递减序列中的点两两相连,所以需要的颜色为序列的长度。我们通过上述解释可以得到一种涂色方式:某节点的颜色为以该节点结尾的最长单调递减序列的长度。
AcCode
#include<algorithm>
#include<iostream>
#include<vector>
#include<cstdio>
#include<map>
#include<set>
#include<string>
#include<cstring>
#include<cmath>
#define int long long
const int N = 1e6 + 100;
int value[N];
int output[N];
int arr[N];
signed main() {
int t;
std::scanf("%lld", &t);
while (t--) {
int n;
std::cin >> n;
for (int i = 1; i <= n; i++) std::scanf("%lld", &value[i]);
output[1] = 1;
int cnt = 1;
arr[0] = value[1];
for (int i = 2; i <= n; i++) {
if (arr[cnt - 1] > value[i]) {
arr[cnt++] = value[i];
output[i] = cnt;
}
else {
int pos = std::upper_bound(arr, arr + cnt, value[i], std::greater<int>()) - (arr);
arr[pos] = value[i];
output[i] = pos + 1;
}
}
std::printf("%lld\n", cnt);
for (int i = 1; i <= n; i++) std::printf("%lld ", output[i]);
std::printf("\n");
}
}