题目描述
Simone, a student of Graph Coloring University, is interested in permutation. Now she is given a permutation of length n n n, and she finds that if she connects each inverse pair, she will get a graph. Formally, for the given permutation, if i < j i<j i<j and a i > a j a_i>a_j ai>aj , then there will be an undirected edge between node i i i and node j j j in the graph.
Then she wants to color this graph. Please achieve poor Simone’s dream. To simplify the problem, you just need to find a way of coloring the vertices of the graph such that no two adjacent vertices are of the same color and minimize the number of colors used.
输入描述:
There are multiple test cases. The first line of the input contains an integer T T T ( 1 ≤ T ≤ 1 0 6 1\leq T\leq 10^6 1≤T≤106), indicating the number of test cases.
For each test case, the first line contains an integer n n n ( 1 ≤ n ≤ 1 0 6 1 \leq n \leq 10^6 1≤n≤106), indicating the length of the permutation.
The second line contains n n n integers a 1 a_1 a1, a 2 a_2 a2,…, a n a_n an , indicating the permutation.
It is guaranteed that the sum of n n n over all test cases does not exceed 1 0 6 10^6 106.
输出描述:
For each test case, the first line contains an integer c c c, the chromatic number(the minimal number of colors been used when coloring) of the graph.
The second line contains n n n integers c 1 c_1 c1, c 2 c_2 c2,…, c n c_n cn , the color of each node.
Notice that c i c_i ci should satisfy the limit that 1 ≤ c i ≤ c 1 \leq c_i \leq c 1≤ci≤c .
If there are several answers, it is acceptable to print any of them.
输入
2
4
1 3 4 2
2
1 2
输出
2
1 1 1 2
1
1 1
方法一
如果给任意一个无向图,完成染色操作,那就不容易做了。主要的方向还是需要从逆序对入手。
做法为:首先将 [ 0 , 1 ] [0,1] [0,1] 所有结点初始染色为 0 0 0 ,然后从 n n n 到 1 1 1 倒序处理,对于每个数字 i i i ,求出下标在 [ 1 , i ] [1,i] [1,i] 区间的最大染色值 m x mx mx,当前结点染为 m x + 1 mx+1 mx+1 。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
struct S{ int l,r,v; }t[N<<2];
int T,n,a[N],pos[N],b[N];
void build(int p,int l,int r){
t[p].l=l,t[p].r=r,t[p].v=0;
if(l==r) return;
int mid=(l+r)>>1;
build(p<<1,l,mid),build(p<<1|1,mid+1,r);
}
int ask(int p,int l,int r){
if(t[p].l>=l&&t[p].r<=r){ return t[p].v; }
int mid=(t[p].l+t[p].r)>>1;
int mx=0;
if(l<=mid) mx=max(mx,ask(p<<1,l,r));
if(r>=mid+1) mx=max(mx,ask(p<<1|1,l,r));
return mx;
}
void change(int p,int x,int v){
if(t[p].l==t[p].r) return (void)(t[p].v=v);
int mid=(t[p].l+t[p].r)>>1;
if(x<=mid) change(p<<1,x,v);
else change(p<<1|1,x,v);
t[p].v=max(t[p<<1].v,t[p<<1|1].v);
}
void solve(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],pos[a[i]]=i;
build(1,1,n);
for(int i=n;i>=1;i--){
b[pos[i]]=ask(1,1,pos[i])+1;
change(1,pos[i],b[pos[i]]);
}
cout<<*max_element(b+1,b+1+n)<<"\n";
for(int i=1;i<=n;i++) cout<<b[i]<<" \n"[i==n];
}
int main(){
ios::sync_with_stdio(false);
for(cin>>T;T;T--) solve();
}
方法二
对于序列中第 i i i 个数字,设下标 [ 0 , i − 1 ] [0,i-1] [0,i−1] 的序列中,最长下降子序列的长度为 l e n len len ,那么当前结点染色为 l e n + 1 len+1 len+1 。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int T,n,a[N],b[N],ls[N];
int get(int l,int r,int x){
while(l<r){
int mid=(l+r)>>1;
if(ls[mid]>x) l=mid+1;
else r=mid;
}
return l;
}
void solve(){
int tot=0; cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++){
if(tot==0||a[i]<ls[tot]) ls[b[i]=++tot]=a[i];
else ls[b[i]=get(1,tot,a[i])]=a[i];
}
cout<<tot<<"\n";
for(int i=1;i<=n;i++) cout<<b[i]<<" \n"[i==n];
}
int main(){
ios::sync_with_stdio(false);
for(cin>>T;T;T--) solve();
}