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; }