BZOJ1006

1006: [HNOI2008]神奇的国度

思路:弦图+完美消除序列
弦图基本知识:戳戳戳!
按照完美消除序列从后向前染色,给每个点染可染颜色最小的
加上优先队列做到 O(nlogn)

既然后面的染色是O(nlogn)了,前面的MCS我们也用优先队列水吧……

代码:
我手写了两个优先队列??

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#define x first
#define y second
using namespace std;
const int MAXN=10010,MAXM=1000010;
pair<int,int> front[MAXM<<1];
int orderx[MAXM<<1],stdx[MAXN];
int n,m;
int num[MAXN];
void sortx()
{
    for (int i=1;i<=m;i++)
        num[front[i].x]++;
    for (int i=1;i<=n;i++) {
        num[i]+=num[i-1];
        stdx[i]=num[i]; }
    for (int i=1;i<=m;i++)
        orderx[++num[front[i].x-1]]=i;
    return ;
}
pair<int,int> heap[MAXN];
int ht;
int point[MAXN];
bool work[MAXN];
int mcs[MAXN];
void swapheap(int l,int r)
{
    swap(heap[l],heap[r]);
    point[heap[l].y]=l;
    point[heap[r].y]=r;
    return ;
}
void adjustdown(int x)
{
    bool next=true;
    while (next) {
        next=false;
        int l=x*2,r=x*2+1;
        if (l<=ht)
            if (r<=ht) {
                if (heap[l]>heap[r] && heap[l]>heap[x]) {
                    swapheap(l,x); x=l; next=true; }
                else if (heap[r]>heap[x]) {
                    swapheap(r,x); x=r; next=true; }}
            else if (heap[l]>heap[x]) {
                swapheap(l,x); x=l; next=true; }}
    return ;
}
void adjustup(int x)
{
    bool next=true;
    while (next) {
        next=false;
        int f=x/2;
        if (f)
            if (heap[x]>heap[f]) {
                swapheap(x,f); x=f; next=true; }}
    return ;
}
void MCS()
{
    int t=0;
    ht=n;
    for (int i=1;i<=ht;i++) {
        heap[i].x=0; heap[i].y=n-i+1; point[n-i+1]=i; }
    while (ht) {
        pair<int,int> now=heap[1];
        work[now.y]=true; mcs[++t]=now.y;
        swapheap(1,ht); ht--; adjustdown(1);
        int x=now.y;
        for (int i=stdx[x-1]+1;i<=stdx[x];i++)
            if (!work[front[orderx[i]].y]) {
                int next=front[orderx[i]].y;
                heap[point[next]].x++;
                adjustup(point[next]); }}
    return ;
}
int color[MAXN];
int c[MAXN];
bool in[MAXN];
void swapc(int l,int r)
{
    swap(c[l],c[r]);
    point[c[l]]=l;
    point[c[r]]=r;
    return ;
}
void cadjustdown(int x)
{
    bool next=true;
    while (next) {
        next=false;
        int l=x*2,r=x*2+1;
        if (l<=ht)
            if (r<=ht) {
                if (c[l]<c[r] && c[l]<c[x]) {
                    swapc(l,x); x=l; next=true; }
                else if (c[r]<c[x]) {
                    swapc(r,x); x=r; next=true; }}
            else if (c[l]<c[x]) {
                swapc(l,x); x=l; next=true; }}
    return ;
}
void cadjustup(int x)
{
    bool next=true;
    while (next) {
        next=false;
        int f=x/2;
        if (f)
            if (c[x]<c[f]) {
                swapc(x,f); x=f; next=true; }}
    return ;
}
int ans;
void init()
{
    cin>>n>>m;
    for (int x,y,i=1;i<=m;i++) {
        scanf("%d%d",&x,&y);
        front[i*2-1].x=x; front[i*2-1].y=y;
        front[i*2].y=x; front[i*2].x=y; }
    m<<=1;
    sortx();
    MCS();
    for (int i=1;i<=n;i++)
        { c[i]=i; point[i]=i; in[i]=true; }
    ht=n;
    int stack[MAXN],top=0;
    for (int i=1;i<=n;i++) {
        int x=mcs[i];
        for (int j=stdx[x-1]+1;j<=stdx[x];j++) {
            int next=front[orderx[j]].y;
            int newc=color[next];
            if (newc && in[newc]) {
                int loc=point[newc]; in[newc]=false; stack[++top]=newc;
                swapc(loc,ht); ht--; cadjustdown(loc); }}
        color[x]=c[1];
        ans=max(color[x],ans);
        while (top) {
            in[stack[top]]=true;
            c[++ht]=stack[top];
            point[stack[top]]=ht;
            cadjustup(ht);
            top--; }}
    cout<<ans<<endl;
    return ;
}
int main()
{
    init();
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值