bzoj1293: [SCOI2009]生日礼物

单调队列

用一个堆维护目前每个颜色在里面的点,每回取出队首点,并更新答案。一旦哪个颜色的点都被用完,跳出循环。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 1000000 + 10;
const int maxk = 60+10;

struct data {
    int a,c;
    
    data(int a,int c):a(a),c(c) {}
    
    bool operator < (const data& rhs) const {
        return a>rhs.a;
    }
};
priority_queue<data>q;
int n,k;
int w[maxk],a[maxn];
int v[maxn],next[maxn],eid,g[maxk];
int ans,tmp;

void addedge(int a,int b) {
    v[eid]=b; next[eid]=g[a]; g[a]=eid++;
}

int main() {
    memset(g,-1,sizeof(g));
    scanf("%d%d",&n,&k);
    for(int i=1;i<=k;i++) {
        scanf("%d",&w[i]);
        for(int j=1;j<=w[i];j++) scanf("%d",&a[j]);
        for(int j=w[i];j;j--) addedge(i,a[j]);
    }
    for(int i=1;i<=k;i++) {
        q.push(data(v[g[i]],i));
        tmp=max(v[g[i]],tmp);
    }
    ans=tmp-q.top().a;
    while(true) {
        data u=q.top(); q.pop();
        //printf("test %d %d \n",u.a,u.c);
        //printf("ok %d %d\n",tmp,ans);
        g[u.c]=next[g[u.c]];
        if(g[u.c]==-1) break;
        q.push(data(v[g[u.c]],u.c));
        tmp=max(tmp,v[g[u.c]]);
        ans=min(ans,tmp-q.top().a);
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2016-05-29 00:50  invoid  阅读(236)  评论(0编辑  收藏  举报