// Piotr Jagiełło #include <cstdio> #include <cassert> #include <queue> #include <algorithm> #include <list> #define MAKS 200010 #define f first #define s second using namespace std; typedef long long int lld; typedef pair<lld,int> para; int n,m; lld t[MAKS]; lld d[MAKS]; list<int> grupy; list<int>::iterator it[MAKS]; bool aktywny[MAKS]; int rozmiar[MAKS]; struct cmp { bool operator()(const para& a, const para& b) { if(a.f!=b.f)return a.f>b.f; if((a.s%3)!=(b.s%3))return (a.s%3)>(b.s%3); return a.s>b.s; } }; priority_queue<para, vector<para>, cmp> kol; bool czekaj; lld dajPrzyrost(int i) { if(i>0 || czekaj==false)return lld(rozmiar[i])*lld(rozmiar[i]+1)/2; else return lld(rozmiar[i]+1)*lld(rozmiar[i]+2)/2 -1; } void wyprodukujZdarzenie(int i) { if(i==grupy.back())return; int j=*(next(it[i])); //fprintf(stderr,"kiedy zapiekanka %d wjedzie w dupe %d?\n",i,j); lld czas; if(i>0 || czekaj==false) czas = (t[j]-t[i])/lld(rozmiar[i]); else czas = t[j]/lld(rozmiar[i]+1); kol.push(para(czas,3*i+2)); //fprintf(stderr,"okazuje sie ze w momencie %lld\n",czas+1); } lld odp[MAKS]; int main() { scanf("%d %d",&n,&m); for(int i=0;i<n;i++) { scanf("%lld",&t[i]); aktywny[i]=true; grupy.push_back(i); it[i]=grupy.end(); it[i]--; rozmiar[i]=1; } for(int i=0;i<m;i++) { scanf("%lld",&d[i]); kol.push(para(d[i],3*i+1)); } czekaj=false; kol.push(para(t[0],0)); lld aktd=0; lld wynik=0; lld przyrost=0; for(int i=0;i<n;i++) { przyrost++; wyprodukujZdarzenie(i); } int zost=m; bool spec=false; lld kumul=przyrost; lld specCzas; while(!kol.empty()) { para p=kol.top(); kol.pop(); lld czas=p.f; lld typ=p.s%3; lld nr=p.s/3; //printf("[%lld] zdarzenie: %lld / %lld\n",czas,typ,nr); //printf("wynik przed: %lld\n",wynik); if(spec && (typ!=2 || czas!=specCzas)) { //printf("skończyły się łączenia, dorzucamy skumulowane %lld\n",kumul); wynik+=kumul; aktd++; //printf("wynik to teraz %lld, aktd: %lld\n",wynik,aktd); spec=false; } if(!spec)kumul=przyrost; //assert(czas>=aktd); wynik+=(czas-aktd)*przyrost; //printf("przyrost: %lld, wynik po: %lld\n",przyrost,wynik); aktd=czas; bool lacz=false; switch(typ) { case 0: // zmiana typu pierwszej grupy //fprintf(stderr,"pierwsza zapiekanka wjezdza na minusy\n"); //assert(nr==0); przyrost-=dajPrzyrost(0); czekaj=true; przyrost+=dajPrzyrost(0); //printf("przyrost to teraz %lld\n",przyrost); wyprodukujZdarzenie(0); break; case 1: // zapytanie odp[nr]=wynik-lld(n)*aktd; zost--; //printf("dla d: %lld wynik to: %lld\n",d[nr],odp[nr]); break; case 2: // łączenie grup if(!aktywny[nr])continue; while(nr!=grupy.back()) { int i=nr; int j=(*(next(it[nr]))); if(max(0LL,t[i]-(aktd+1))+lld(rozmiar[i])*(aktd+1) > t[j]-(aktd+1)) { //printf("zapiekanka %d wchlania %d\n",i,j); lacz=true; aktywny[j]=false; grupy.erase(it[j]); // przyrost chwilowy lld r=max(0LL,t[i]-(aktd+1))+lld(rozmiar[i])*(aktd+1) - (t[j]-(aktd+1)); kumul+=r*lld(rozmiar[j]); //printf("r: %lld, skumulowany przyrost chwilowy: %lld\n",r,kumul); // przyrost na przyszlosc przyrost-=dajPrzyrost(i); przyrost-=dajPrzyrost(j); rozmiar[i]+=rozmiar[j]; przyrost+=dajPrzyrost(i); //printf("przyrost to teraz %lld\n",przyrost); } else break; } if(lacz) { spec=true; specCzas=aktd; wyprodukujZdarzenie(nr); } break; } if(zost==0)break; } for(int i=0;i<m;i++)printf("%lld\n",odp[i]); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | // Piotr Jagiełło #include <cstdio> #include <cassert> #include <queue> #include <algorithm> #include <list> #define MAKS 200010 #define f first #define s second using namespace std; typedef long long int lld; typedef pair<lld,int> para; int n,m; lld t[MAKS]; lld d[MAKS]; list<int> grupy; list<int>::iterator it[MAKS]; bool aktywny[MAKS]; int rozmiar[MAKS]; struct cmp { bool operator()(const para& a, const para& b) { if(a.f!=b.f)return a.f>b.f; if((a.s%3)!=(b.s%3))return (a.s%3)>(b.s%3); return a.s>b.s; } }; priority_queue<para, vector<para>, cmp> kol; bool czekaj; lld dajPrzyrost(int i) { if(i>0 || czekaj==false)return lld(rozmiar[i])*lld(rozmiar[i]+1)/2; else return lld(rozmiar[i]+1)*lld(rozmiar[i]+2)/2 -1; } void wyprodukujZdarzenie(int i) { if(i==grupy.back())return; int j=*(next(it[i])); //fprintf(stderr,"kiedy zapiekanka %d wjedzie w dupe %d?\n",i,j); lld czas; if(i>0 || czekaj==false) czas = (t[j]-t[i])/lld(rozmiar[i]); else czas = t[j]/lld(rozmiar[i]+1); kol.push(para(czas,3*i+2)); //fprintf(stderr,"okazuje sie ze w momencie %lld\n",czas+1); } lld odp[MAKS]; int main() { scanf("%d %d",&n,&m); for(int i=0;i<n;i++) { scanf("%lld",&t[i]); aktywny[i]=true; grupy.push_back(i); it[i]=grupy.end(); it[i]--; rozmiar[i]=1; } for(int i=0;i<m;i++) { scanf("%lld",&d[i]); kol.push(para(d[i],3*i+1)); } czekaj=false; kol.push(para(t[0],0)); lld aktd=0; lld wynik=0; lld przyrost=0; for(int i=0;i<n;i++) { przyrost++; wyprodukujZdarzenie(i); } int zost=m; bool spec=false; lld kumul=przyrost; lld specCzas; while(!kol.empty()) { para p=kol.top(); kol.pop(); lld czas=p.f; lld typ=p.s%3; lld nr=p.s/3; //printf("[%lld] zdarzenie: %lld / %lld\n",czas,typ,nr); //printf("wynik przed: %lld\n",wynik); if(spec && (typ!=2 || czas!=specCzas)) { //printf("skończyły się łączenia, dorzucamy skumulowane %lld\n",kumul); wynik+=kumul; aktd++; //printf("wynik to teraz %lld, aktd: %lld\n",wynik,aktd); spec=false; } if(!spec)kumul=przyrost; //assert(czas>=aktd); wynik+=(czas-aktd)*przyrost; //printf("przyrost: %lld, wynik po: %lld\n",przyrost,wynik); aktd=czas; bool lacz=false; switch(typ) { case 0: // zmiana typu pierwszej grupy //fprintf(stderr,"pierwsza zapiekanka wjezdza na minusy\n"); //assert(nr==0); przyrost-=dajPrzyrost(0); czekaj=true; przyrost+=dajPrzyrost(0); //printf("przyrost to teraz %lld\n",przyrost); wyprodukujZdarzenie(0); break; case 1: // zapytanie odp[nr]=wynik-lld(n)*aktd; zost--; //printf("dla d: %lld wynik to: %lld\n",d[nr],odp[nr]); break; case 2: // łączenie grup if(!aktywny[nr])continue; while(nr!=grupy.back()) { int i=nr; int j=(*(next(it[nr]))); if(max(0LL,t[i]-(aktd+1))+lld(rozmiar[i])*(aktd+1) > t[j]-(aktd+1)) { //printf("zapiekanka %d wchlania %d\n",i,j); lacz=true; aktywny[j]=false; grupy.erase(it[j]); // przyrost chwilowy lld r=max(0LL,t[i]-(aktd+1))+lld(rozmiar[i])*(aktd+1) - (t[j]-(aktd+1)); kumul+=r*lld(rozmiar[j]); //printf("r: %lld, skumulowany przyrost chwilowy: %lld\n",r,kumul); // przyrost na przyszlosc przyrost-=dajPrzyrost(i); przyrost-=dajPrzyrost(j); rozmiar[i]+=rozmiar[j]; przyrost+=dajPrzyrost(i); //printf("przyrost to teraz %lld\n",przyrost); } else break; } if(lacz) { spec=true; specCzas=aktd; wyprodukujZdarzenie(nr); } break; } if(zost==0)break; } for(int i=0;i<m;i++)printf("%lld\n",odp[i]); } |