P2564 [SCOI2009]生日礼物
*预处理:把m个区间合并成一个大区间(按照横坐标排序即可)
*思路:因为我们要一段尽可能小的区间包含所有的彩带种类,我们不防开一个数组,记录当前区间内每种彩带多有多少个,从[1,1]开始,如果当前彩带种类<k,则右端点向右移,把该种彩带在区间内的数量+1,如果该种彩带的数量从0->1,即说明这是一条新彩带,彩带种类+1,当彩带种类==m时,记录下当前区间长度,把左端点向右移,把该种彩带在区间内的数量-1,如果该种彩带的数量从1->0,说明该种彩带不包含在区间里。彩带种类-1
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <queue> 5 #include <cmath> 6 using namespace std; 7 int n,m,a[1000005],b[20005],k,l,r,t,ans=0; 8 struct node{ 9 int pos,val; 10 }num[1000005]; 11 bool cmp(node a,node b){ 12 return a.pos<b.pos; 13 } 14 int main() 15 { 16 17 scanf("%d%d",&n,&m); 18 for(int i=1;i<=m;i++){ 19 scanf ("%d",&t); 20 for (int j = 1;j <= t;j++){ 21 scanf ("%d",&num[++ans].pos); 22 num[ans].val=i; 23 } 24 } 25 sort(num+1,num+ans+1,cmp); 26 l=1; r=1; k=1; b[num[1].val]=1; int tmp=2000000005; 27 while(l<=r && r<=n){ 28 while(k==m){ 29 tmp=min(tmp,num[r].pos-num[l].pos); 30 b[num[l].val]--; 31 if(b[num[l].val]==0) k--; 32 l++; 33 } 34 r++, b[num[r].val]++; 35 if(b[num[r].val]==1) k++; 36 } 37 cout<<tmp<<endl; 38 return 0; 39 }