【BZOJ4293】Siano(PA2015)-線段樹+二分
阿新 • • 發佈:2018-12-12
測試地址:Siano 題目大意: 有片草,第片草每天長高米,次操作,每次操作在第天把所有草高於某個數的部分割掉,求每次割下的草的高度和。 做法: 本題需要用到線段樹+二分。 挺神的一道題…注意到每次割草,被割的草都不一定是一個區間,很難處理,因此想到通過某種辦法把每次操作的修改變成一個區間。 觀察發現,在任何時刻,大的草的高度一定不會比小的草矮。因此我們把草按從小到大排序,這樣每次被割的草一定是一段字尾,只需要二分就可以找到這樣的字尾。 涉及區間修改,還要支援二分,所以想到線上段樹上二分。我們要維護的是每片草現在的高度,那麼第天第片草的高度是:,其中為這片草上次被割的時間,為這片草上次被割後剩下的高度。顯然這個可以寫成,前面的部分僅隨著的變化而變化,而後面的資訊都可以線上段樹上維護出來。在詢問時,答案就是被割的草的高度之和,再減去這些草的片數乘上。這樣我們就以的時間複雜度解決了此題。 以下是本人程式碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
ll a[500010]={0},sum[500010],d[500010],b[500010];
ll nowday,based[2000010]={0},rhtbased[ 2000010];
int rhtop[2000010]={0},optag[2000010]={0};
void update(int no,int op,int l,int r)
{
rhtop[no]=optag[no]=op;
based[no]=b[optag[no]]*(ll)(r-l+1)-d[optag[no]]*(sum[r]-sum[l-1]);
rhtbased[no]=b[optag[no]]-d[optag[no]]*a[r];
}
void pushdown(int no,int l,int r)
{
int mid=(l+r)>>1;
if (optag[no]>0)
{
update(no<<1,optag[no],l,mid);
update(no<<1|1,optag[no],mid+1,r);
optag[no]=0;
}
}
void pushup(int no)
{
rhtop[no]=rhtop[no<<1|1];
rhtbased[no]=rhtbased[no<<1|1];
based[no]=based[no<<1]+based[no<<1|1];
}
int find(int no,int l,int r,ll x)
{
if (l==r)
{
if (nowday*a[l]+based[no]<=x) return l+1;
else return l;
}
int mid=(l+r)>>1;
pushdown(no,l,r);
if (nowday*a[mid]+rhtbased[no<<1]>x)
return find(no<<1,l,mid,x);
else return find(no<<1|1,mid+1,r,x);
}
void modify(int no,int l,int r,int x,int op)
{
if (l>=x)
{
update(no,op,l,r);
return;
}
int mid=(l+r)>>1;
pushdown(no,l,r);
if (mid>=x) modify(no<<1,l,mid,x,op);
modify(no<<1|1,mid+1,r,x,op);
pushup(no);
}
ll query(int no,int l,int r,int x)
{
if (l>=x) return nowday*(sum[r]-sum[l-1])+based[no];
ll ans=0;
int mid=(l+r)>>1;
pushdown(no,l,r);
if (mid>=x) ans+=query(no<<1,l,mid,x);
ans+=query(no<<1|1,mid+1,r,x);
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
sum[0]=0;
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+a[i];
for(int i=1;i<=m;i++)
{
scanf("%lld%lld",&d[i],&b[i]);
nowday=d[i];
int pos=find(1,1,n,b[i]);
if (pos==n+1) printf("0\n");
else
{
printf("%lld\n",query(1,1,n,pos)-(ll)(n-pos+1)*b[i]);
modify(1,1,n,pos,i);
}
}
return 0;
}