上次写接水果的时候看出来是整体二分了 但是板子有点忘了所以复习一下。
上例题:LINK:bzoj2527
好像以前写过 那就再写一遍.
求每个国家收集齐陨石的最早时间。
模拟显然过不了 我们可以二分一个时间。
考虑判定 如果我们能求出sum[i][j]表示前i个时间之内对于j国家能收集到的陨石个数那么即可完成判定。
显然在求出这个数组的时候我们都能求出来答案了...
所有的询问都要二分,所以直接上整体二分。二分内部线段树区间修改+每个国家暴力查询即可。
复杂度 mlog^2. 区间修改单点查询 直接上树状数组即可. 这题卡常 我想用线段树是不可能过掉这道题的...
```
const int MAXN=300010;
int n,m,p,t;
int a[MAXN],ans[MAXN];
LL c[MAXN];
struct wy
{
int op,x,y;
int k;
}q[MAXN<<1],ql[MAXN<<1],qr[MAXN<<1];
inline void add(RE int x,RE int y)
{
while(x<=m)
{
c[x]+=y;
x+=x&(-x);
}
return;
}
inline LL ask(RE int x)
{
LL cnt=0;
while(x)
{
cnt+=c[x];
x-=x&(-x);
}
return cnt;
}
vectorw[MAXN];
inline void add1(int x,int y,int z)
{
add(x,z);
add(y+1,-z);
}
inline void solve(int l,int r,int L,int R)
{
if(l>r)return;
if(L==R)
{
for(int i=l;i<=r;++i)if(op(i)==0)ans[x(i)]=L;
return;
}
RE int mid=(L+R)>>1;
RE int ll=0,rr=0;
for(int i=l;i<=r;++i)
{
if(!op(i))
{
RE int x=x(i);RE LL cnt=0;
for(int j=0;j=k(i))break;
}
if(cnt>=k(i))ql[++ll]=q[i];
else k(i)-=cnt,qr[++rr]=q[i];
}
else
{
if(op(i)<=mid)
{
ql[++ll]=q[i];
if(x(i)>y(i))add1(x(i),m,k(i)),add1(1,y(i),k(i));
else add1(x(i),y(i),k(i));
}
else qr[++rr]=q[i];
}
}
for(int i=1;i<=ll;++i)
{
if(ql[i].op)
{
if(ql[i].x>ql[i].y)add1(ql[i].x,m,-ql[i].k),add1(1,ql[i].y,-ql[i].k);
else add1(ql[i].x,ql[i].y,-ql[i].k);
}
q[l+i-1]=ql[i];
}
for(int i=1;i<=rr;++i)q[l+ll+i-1]=qr[i];
solve(l,l+ll-1,L,mid);
solve(l+ll,r,mid+1,R);
}
int main()
{
freopen("1.in","r",stdin);
n=read();m=read();
for(RE int i=1;i<=m;++i)
{
RE int x;
x=read();
w[x].push_back(i);
}
for(RE int i=1;i<=n;++i)a[i]=read();
p=read();
for(RE int i=1;i<=p;++i)
{
op(++t)=i;x(t)=read();
y(t)=read();k(t)=read();
}
for(RE int i=1;i<=n;++i)op(++t)=0,x(t)=i,k(t)=a[i];
solve(1,t,1,p+1);
for(int i=1;i<=n;++i)if(ans[i]!=p+1)printf("%d
",ans[i]);else puts("NIE");
return 0;
}
```