【LuoguP3616】富金森林公園-線段樹
阿新 • • 發佈:2018-11-07
測試地址:富金森林公園
做法: 本題需要用到線段樹。
一道好題,不看題解乍一下真的不知道怎麼做…
我們考慮直接維護水面在高度
時能看見的連續段數
,考慮一塊石頭高度的增減對
的影響。為了討論方便,我們把修改操作都看成是,先把石頭高度降到最低,再把石頭高度升到新的高度,這樣只用考慮兩個過程就可以了,並且我們發現這兩個過程產生的貢獻完全相反,因此我們現在只考慮升的過程就好了。
考慮這塊石頭相鄰的兩塊石頭高度
,假定
,那麼在當前石頭升到高度
這一段,水面高度在這一段時的答案應該
,因為兩塊被連線成一塊;而在高度從
升到
的這一段,水面高度為這一段時的答案不發生變化,因為原來是一段,現在還是一段;當升到比
高時,水面高度為這一段時的答案會
,因為原來這裡沒有石頭,現在多出來了一塊。這樣討論之後,我們發現用線段樹進行區間修改就能完成這一題了,時間複雜度為
。
以下是本人程式碼:
#include <bits/stdc++.h>
using namespace std;
int n,m,tot,a[200010]={0},h[200010],op[200010],opx[200010],opid[200010];
int seg[2000010]={0},tag[2000010]={0};
struct forsort
{
bool type;
int id,val;
}f[400010];
bool cmp(forsort a,forsort b)
{
return a.val<b.val;
}
void pushdown(int no,int l,int r)
{
int mid=(l+r)>>1;
if (tag[no]!=0)
{
tag[no<<1]+=tag[no],tag[no<<1|1]+=tag[no];
seg[no<<1]+=tag[no]*(mid-l+1);
seg[no<<1|1]+=tag[no]*(r-mid);
tag[no]=0;
}
}
void pushup(int no)
{
seg[no]=seg[no<<1]+seg[no<<1|1];
}
void segmodify(int no,int l,int r,int s,int t,int d)
{
if (l>=s&&r<=t)
{
seg[no]+=(r-l+1)*d;
tag[no]+=d;
return;
}
int mid=(l+r)>>1;
pushdown(no,l,r);
if (s<=mid) segmodify(no<<1,l,mid,s,t,d);
if (t>mid) segmodify(no<<1|1,mid+1,r,s,t,d);
pushup(no);
}
int query(int no,int l,int r,int x)
{
if (l==r) return seg[no];
int mid=(l+r)>>1;
pushdown(no,l,r);
if (x<=mid) return query(no<<1,l,mid,x);
else return query(no<<1|1,mid+1,r,x);
}
void modify(int id,int type)
{
if (min(a[id],min(a[id-1],a[id+1]))>0)
segmodify(1,1,tot,1,min(a[id],min(a[id-1],a[id+1])),-type);
if (a[id]>max(a[id-1],a[id+1]))
segmodify(1,1,tot,max(a[id-1],a[id+1])+1,a[id],type);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&f[i].val);
f[i].type=0,f[i].id=i;
}
for(int i=1;i<=m;i++)
{
scanf("%d",&op[i]);
if (op[i]==1) scanf("%d",&f[n+i].val);
else scanf("%d%d",&opid[i],&f[n+i].val);
f[n+i].type=1,f[n+i].id=i;
}
sort(f+1,f+n+m+1,cmp);
tot=0;
for(int i=1;i<=n+m;i++)
{
if (i==1||f[i].val!=f[i-1].val)
tot++;
if (!f[i].type) h[f[i].id]=tot;
else opx[f[i].id]=tot;
}
for(int i=1;i<=n;i++)
{
a[i]=h[i];
modify(i,1);
}
for(int i=1;i<=m;i++)
{
if (op[i]==1) printf("%d\n",query(1,1,tot,opx[i]));
else
{
modify(opid[i],-1);
a[opid[i]]=opx[i];
modify(opid[i],1);
}
}
return 0;
}