//d側を1個消すとc側が1個増えるので、dの大きい方から消していく //実質的に解説の最小全域木を求めているのと同じ(はず) #include #include #define ll long long #define rep(i,l,r)for(ll i=l;i(q)?(p):(q)) //seg木ここから //↓ここを変える //cの区間minとdのdelcntが数えられれば良い typedef struct atai{ll c,d;}atai; atai xx(atai x,atai y){ atai ret; ret.c=min(x.c,y.c); ret.d=x.d+y.d; return ret; } int segNUM; atai segN[1<<21],*seg; void seguse(int n){segNUM=n;seg=segN+segNUM;} //seg[]に値を与えてから初期化 void seginit(){for(int node=segNUM-1;node;node--)segN[node]=xx(segN[node*2],segN[node*2+1]);} void segupdate(int node,atai x){ //seg[node]をxに更新 node+=segNUM; segN[node]=x; while(node/=2)segN[node]=xx(segN[node*2],segN[node*2+1]); } atai segcalcsub(int l,int r,int k,int cl,int cr){ //完全に含むとき if(l<=cl&&cr<=r)return segN[k]; int cm=(cl+cr)/2; //左側だけ if(r<=cm)return segcalcsub(l,r,2*k ,cl,cm); //右側だけ if(cm<=l)return segcalcsub(l,r,2*k+1,cm,cr); //両方 return xx(segcalcsub(l,r,2*k,cl,cm),segcalcsub(l,r,2*k+1,cm,cr)); } atai segcalc(int l,int r){return segcalcsub(l,r,1,0,segNUM);} int n; int left,right; void bs(ll i){ //iの属する区間を求めたい ll ng=0,ok=i; while(ok-ng>1){ ll m=(ok+ng)/2; if(segcalc(m,i).d==0)ok=m; else ng=m; } left=ng; ok=i,ng=n+1; while(ng-ok>1){ ll m=(ok+ng)/2; if(segcalc(i,m).d==0)ok=m; else ng=m; } right=ok; } ll d[100010]; ll idx[100010]; int hikaku(const void*a,const void*b){ //dの降順にindexを並べる if(d[*(ll*)a]>d[*(ll*)b])return -1; if(d[*(ll*)a]