P4198 樓房重建
線段樹維護以某點為開頭的最長不下降子序列
使用下面calc函數能夠計算線段樹u維護的區間中,以x為開頭最長不下降子序列的個數。
calc需要維護區間最值。
template<typename T>
int calc(int u
,T x
)
{if(tree
[u
].l
==tree
[u
].r
) return tree
[u
].v
>x
?1:0;if(tree
[u
<<1].v
<=x
) return calc(u
<<1|1,x
);return tree
[u
].cnt
-tree
[u
<<1].cnt
+calc(u
<<1,x
);
}
B-xay loves monotonicity
如果本題沒有b數組,就是上面的樓房重建,用上面calc函數遞歸解決問題。
由于存在b數組的操作,首先是區間翻轉可以懶標記解決。
對于貢獻來說我們同樣記錄每個區間的最值,并且記錄一下最值出現位置pos\text {pos}pos的bposb_{\text{pos}}bpos?值,然后calc過程中記錄一個pre即可實現遞歸。
注意引用的巧妙使用!!!
由于引用不難知道:
int calc(int u,int &mx,int &pre)中的mx\text{mx}mx和pre\text{pre}pre始終表示當前考慮的子序列最后一個值和最后一個值的b
#include<bits/stdc++.h>
using namespace std
;
using ll
=long long;
template <class T=int> T
rd()
{T res
=0;T fg
=1;char ch
=getchar();while(!isdigit(ch
)) {if(ch
=='-') fg
=-1;ch
=getchar();}while( isdigit(ch
)) res
=(res
<<1)+(res
<<3)+(ch
^48),ch
=getchar();return res
*fg
;
}
const int N
=200010;
int a
[N
],b
[N
],n
,m
;
struct node
{int l
,r
;int v
,cnt
;int bt
,tag
;
}tree
[N
<<2];
void pushdown(int u
)
{if(!tree
[u
].tag
) return;tree
[u
<<1].tag
^=1;tree
[u
<<1|1].tag
^=1;tree
[u
<<1].bt
^=1;tree
[u
<<1|1].bt
^=1;tree
[u
].tag
=0;
}
int calc(int u
,int &mx
,int &pre
)
{if(tree
[u
].v
<mx
) return 0;if(tree
[u
].l
==tree
[u
].r
){if(tree
[u
].v
>=mx
) {int ans
=(tree
[u
].bt
!=pre
); mx
=tree
[u
].v
,pre
=tree
[u
].bt
;return ans
;}return 0;}pushdown(u
);if(tree
[u
<<1].v
<mx
) return calc(u
<<1|1,mx
,pre
);int ans
=calc(u
<<1,mx
,pre
)+tree
[u
].cnt
-tree
[u
<<1].cnt
;mx
=tree
[u
].v
,pre
=tree
[u
].bt
;return ans
;}
void pushup(int u
)
{if(tree
[u
<<1].v
>tree
[u
<<1|1].v
)tree
[u
].v
=tree
[u
<<1].v
,tree
[u
].bt
=tree
[u
<<1].bt
;elsetree
[u
].v
=tree
[u
<<1|1].v
,tree
[u
].bt
=tree
[u
<<1|1].bt
;int mx
=tree
[u
<<1].v
,pre
=tree
[u
<<1].bt
;tree
[u
].cnt
=tree
[u
<<1].cnt
+calc(u
<<1|1,mx
,pre
);
}
void build(int u
,int l
,int r
)
{tree
[u
]={l
,r
};if(l
==r
){tree
[u
].v
=a
[l
];tree
[u
].bt
=b
[l
];tree
[u
].cnt
=1;return;}int mid
=l
+r
>>1;build(u
<<1,l
,mid
),build(u
<<1|1,mid
+1,r
);pushup(u
);
}
void change(int u
,int pos
,int v
)
{if(tree
[u
].l
==tree
[u
].r
) return tree
[u
].v
=v
,void();pushdown(u
);int mid
=tree
[u
].l
+tree
[u
].r
>>1;if(pos
<=mid
) change(u
<<1,pos
,v
);elsechange(u
<<1|1,pos
,v
);pushup(u
);
}
void filp(int u
,int l
,int r
)
{if(l
<=tree
[u
].l
&&tree
[u
].r
<=r
){tree
[u
].bt
^=1;tree
[u
].tag
^=1;return;}pushdown(u
);int mid
=tree
[u
].l
+tree
[u
].r
>>1;if(l
<=mid
) filp(u
<<1,l
,r
);if(r
>mid
)filp(u
<<1|1,l
,r
);pushup(u
);
}
int query(int u
,int l
,int r
,int &mx
,int &pre
)
{if(l
<=tree
[u
].l
&&tree
[u
].r
<=r
) return calc(u
,mx
,pre
);pushdown(u
);int mid
=tree
[u
].l
+tree
[u
].r
>>1;int v
=0;if(l
<=mid
) v
+=query(u
<<1,l
,r
,mx
,pre
);if(r
>mid
)v
+=query(u
<<1|1,l
,r
,mx
,pre
);return v
;
}
int main()
{n
=rd();for(int i
=1;i
<=n
;i
++) a
[i
]=rd();for(int i
=1;i
<=n
;i
++) b
[i
]=rd();build(1,1,n
);m
=rd();while(m
--){int op
=rd(),t1
=rd(),t2
=rd();if(op
==1) change(1,t1
,t2
);else if(op
==2) filp(1,t1
,t2
);else{int mx
=-1,pre
=-1;printf("%d\n",query(1,t1
,t2
,mx
,pre
)-1);}}return 0;
}
總結
以上是生活随笔為你收集整理的2021牛客暑期多校训练营7 B-xay loves monotonicity(线段树+不降子序列)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。