原题: http://codeforces.com/gym/102006/problem/K
题意: n个数,每个数会往左右最近的比它大的数连边,要求直接相连的点不能染相同颜色,问最小的颜色数量。
解析:
直接连边暴力染色即可。这个如果建树的话,就是笛卡尔树加上一些边,画出来一定是很多个三角形拼起来,那么显然最后的答案最多只有3。
不知道是不是oj的问题,不同的连边方式就错了。。。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);++i)
#define repp(i,b,a) for(int i=(int)(b);i>=(int)(a);--i)
const int maxn=1e6+6;
int a[maxn];
int sta[maxn],top;
int head[maxn],to[maxn<<2],nex[maxn<<2],now;
void Add(int a,int b){
//if(a<b)printf("add %d %d\n",a,b);
nex[++now]=head[a];head[a]=now;to[now]=b;
}
int c[maxn];
bool v[4];
void dfs(int p){
if(c[p])return;
rep(i,1,3)v[i]=0;
for(int i=head[p];i;i=nex[i]){
int u=to[i];
if(c[u]){
v[c[u]]=1;
}
}
rep(i,1,3){
if(!v[i]){
c[p]=i;break;
}
}
for(int i=head[p];i;i=nex[i]){
int u=to[i];
if(!c[u]){
dfs(u);
}
}
}
int main(){
//freopen("tour.in","r",stdin);
ios::sync_with_stdio(false);
cin.tie(0);
int t;cin>>t;++t;
while(--t){
now=0;
int n;cin>>n;
rep(i,1,n)c[i]=0,head[i]=0;
rep(i,1,n)cin>>a[i];
top=0;
rep(i,1,n){
while(top&&a[sta[top]]<a[i]){
//Add(sta[top],i),Add(i,sta[top]);
--top;
}
if(top)Add(sta[top],i),Add(i,sta[top]);//将这一行换成上面那行就错了,莫名其妙
sta[++top]=i;
}
top=0;
repp(i,n,1){
while(top&&a[sta[top]]<a[i]){
//Add(sta[top],i),Add(i,sta[top]);
--top;
}
if(top)Add(sta[top],i),Add(i,sta[top]);
sta[++top]=i;
}
rep(i,1,n)
dfs(i);
int ans=1;
rep(i,1,n)ans=max(ans,c[i]);
cout<<ans<<endl;
rep(i,1,n){
cout<<c[i]<<(i==n?'\n':' ');
}
}
}