线段树维护区间最大值+第 45 届(ICPC)亚洲区域赛(昆明)L题Simone and Graph Coloring

题意:

给你n个数的序列,当满足 i < j i<j i<j a n d and and a i > a j a_i>a_j ai>aj时,这两个点之间有一条边,现在对点染色,要求每个点相邻的点颜色不同,问如何染色使得不同颜色数量最小。

题目:

链接:https://ac.nowcoder.com/acm/contest/17137/L
来源:牛客网

Simone, a student of Graph Coloring University, is interested in permutation. Now she is given a permutation of length nn, 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 a n d and and a i > a j a_i>a_j ai>aj, then there will be an undirected edge between node i and node 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 ( 1 ≤ T ≤ 1 0 6 ) T(1\leq T\leq 10^6) T(1T106) , indicating the number of test cases.

For each test case, the first line contains an integer n ( 1 ≤ n ≤ 1 0 6 ) n(1 \leq n \leq 10^6) n(1n106), indicating the length of the permutation.

The second line contains nn integers a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an , indicating the permutation.

It is guaranteed that the sum of nn over all test cases does not exceed 1 0 6 10^6 106 .

输出描述:

For each test case, the first line contains an integer cc, the chromatic number(the minimal number of colors been used when coloring) of the graph.

The second line contains nn integers c 1 , c 2 , . . . , c n c_1,c_2,...,c_n c1,c2,...,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 1cic If there are several answers, it is acceptable to print any of them.

示例1
输入

2
4
1 3 4 2
2
1 2

输出

2
1 1 1 2
1
1 1

分析:

这道题,在赛中时,刚开始考虑是直接求每个元素的逆序对(用树状数组),然后该点颜色为逆序对数+1,交了wa了第一遍;第二遍我们举出来了一个数据是 1 5 2 3 4,结果是 1 4 1 1 1,颜色数为4,肯定不对,所以进行了离散化,交上去又wa了,此时走入了瓶颈,举了很多数据都是对的,耽误了很多时间,最后举了一个例子,1 2 3 4 5 8 6 9 7,按着思路应该是1 1 1 1 1 3 1 2 1,但有更优解 1 1 1 1 1 2 1 2 1,故此,我们思路出问题了。讨论过后很短的时间,就决定用线段树维护区间逆序对颜色最大值,每次query得到最大值+1即可。这里面有几个需要注意的点:

  • 序列从后往前遍历,当我们对当前区间查找最大值时,就是当前点逆序对的最大值,因为某些虽然比当前点小,但不为逆序对的值,一定在序列的后面,此时该点并没有赋值,所以不需考虑。
  • 区间更新时,因为少加了seg[u]=max(seg[u<<1],seg[u<<1|1]);,编译结果出现问题,就像前面说的,我们需要的是区间最大值,直接套用模板就行,不需要考虑逆序对之类的。最后每次更新颜色最大值,输出即可,orz%%%%%%一道签到题搞芥末久,果然还是菜哈。

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
int n;
int a[N],b[N];
int seg[N<<2];
void upd(int l,int t,int u,int L,int R){
    if(L==l && R==l){
        seg[u]=t;
        return;
    }
    int md=(L+R)>>1;
    if(l<=md) upd(l,t,u<<1,L,md);
    if(l>md)  upd(l,t,u<<1|1,md+1,R);
    seg[u]=max(seg[u<<1],seg[u<<1|1]);
}
int quy(int l,int r,int u,int L,int R){
    if(l<=L && r>=R){
        return seg[u];
    }
    int md=(L+R)>>1;
    int tp=0;
    if(l<=md) tp=max(tp,quy(l,r,u<<1,L,md));
    if(r>md)  tp=max(tp,quy(l,r,u<<1|1,md+1,R));
    return tp;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--){

        for(int i=1; i<4*n+100; ++i) seg[i]=0;
        scanf("%d",&n);
        for(int i=1; i<=n; ++i){
            scanf("%d",&a[i]);
        }
        int ma=0;
        for(int i=n; i>=1; --i){
            b[i]=quy(1,a[i],1,1,n)+1;
            upd(a[i],b[i],1,1,n);
            ma=max(ma,b[i]);
        }
        printf("%d\n",ma);
        for(int i=1; i<=n; ++i){
            printf("%d%c",b[i],(i==n?'\n':' '));
        }
    }
    return 0;
}


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值