2021牛客多校7 - xay loves monotonicity(线段树区间合并)
題目鏈接:點(diǎn)擊查看
題目大意:給出一個長度為 nnn 的數(shù)字序列 aaa 和 010101 序列 bbb,需要執(zhí)行 mmm 次操作,每次操作分為如下三種類型:
最后說一下區(qū)間 [l,r][l,r][l,r] 的貢獻(xiàn)為,首先找到區(qū)間 [l,r][l,r][l,r] 內(nèi)的 “最長不下降子序列”,設(shè)其為 {p1,p2,...,pk}\{p_1,p_2,...,p_k\}{p1?,p2?,...,pk?},需要滿足:
然后將數(shù)組 bbb 中相應(yīng)的 010101 序列取出,即 {bp1,bp2,bp3,...,bpk}\{b_{p_1},b_{p_2},b_{p_3},...,b_{p_k}\}{bp1??,bp2??,bp3??,...,bpk??}
貢獻(xiàn)就是 ∑i=1k[bi≠bi?1]\sum\limits_{i=1}^{k}[b_i \neq b_{i-1}]i=1∑k?[bi??=bi?1?]
題目分析:弱化版:HDU - 6406
其實(shí)這個題在思路上和弱化版沒有區(qū)別,只是加了些許條件,只需要對 calcalcal 函數(shù)進(jìn)行一下魔改就可以了
先回顧一下簡單版本,如果只需要求解 “最長不下降子序列” 的個數(shù),那么定義 cal(k,mx)cal(k,mx)cal(k,mx) 為前一項(xiàng)為 mxmxmx ,線段樹的節(jié)點(diǎn) kkk 所提供的貢獻(xiàn)。如何求解?線段樹維護(hù)一下區(qū)間的最大值,分成兩種情況討論:
這里為了方便追蹤 mxmxmx 的狀態(tài),我們將其作為引用或者全局變量進(jìn)行傳值,因?yàn)樵诰€段樹中檢索的順序是先左后右,宏觀來看就是從左向右掃描序列的過程,所以實(shí)時更新 mxmxmx 也就模擬了題目中的不斷尋找 “最長不下降子序列” 的過程了。
然后就是我們發(fā)現(xiàn)上面的第二種情況的復(fù)雜度有點(diǎn)不樂觀,但是我們不難看出,在遞歸完左子樹后,右子樹的答案就完全受左子樹所影響了,而對于子樹 kkk 來說,我們早就通過 pushuppushuppushup 維護(hù)好答案了,所以可以 O(1)O(1)O(1) 計算右子樹的貢獻(xiàn)為 cnt[k]?cnt[lc[k]]cnt[k]-cnt[lc[k]]cnt[k]?cnt[lc[k]]
所以就簡單描述出了弱化版本的 O(nlog2n)O(nlog^2n)O(nlog2n) 的做法
回到本題我們該如何維護(hù)該序列映射到數(shù)組 bbb 上的貢獻(xiàn)呢,其實(shí)只需要在 calcalcal 函數(shù)中額外維護(hù)一個參數(shù)就可以了:cal(k,mx,pre)cal(k,mx,pre)cal(k,mx,pre) 代表的是,前一項(xiàng)為 mxmxmx,mxmxmx 所代表的位置的 bbb 的狀態(tài)為 preprepre,子樹 kkk 所提供的貢獻(xiàn)。在 calcalcal 遞歸到葉子節(jié)點(diǎn)時直接計算答案就好了
需要注意的是,在上述兩種情況中的第二種情況,雖然優(yōu)化了訪問右子樹的過程,但是返回的時候別忘了更新 mxmxmx 和 preprepre 為右子樹結(jié)束時的狀態(tài)(因?yàn)橐獜淖蟮接覓呙柙蛄?#xff09;
剩下的兩種操作無非就是單點(diǎn)修改和區(qū)間修改,中規(guī)中矩的線段樹操作就不多說了
計算答案時的初始值根據(jù)題意設(shè)置成 a[l]a[l]a[l] 和 b[l]b[l]b[l] 就可以了
代碼:
// Problem: xay loves monotonicity // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/11258/B // Memory Limit: 524288 MB // Time Limit: 4000 ms // // Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2) // #pragma GCC optimize("Ofast","inline","-ffast-math") // #pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<list> #include<unordered_map> #define lowbit(x) (x&-x) using namespace std; typedef long long LL; typedef unsigned long long ull; template<typename T> inline void read(T &x) {T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f; } template<typename T> inline void write(T x) {if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0'); } const int inf=0x3f3f3f3f; const int N=1e6+100; struct Node {int l,r;int mmax,flag,lazy,cnt; }tree[N<<2]; int a[N],b[N]; void pushdown(int k) {if(tree[k].lazy) {tree[k].lazy=0;tree[k<<1].flag^=1,tree[k<<1|1].flag^=1;tree[k<<1].lazy^=1,tree[k<<1|1].lazy^=1;} } int cal(int k,int &mx,int &pre) {//在子樹k中以mx為起點(diǎn)的貢獻(xiàn),pre為mx位置的b的值if(tree[k].mmax<mx) return 0;if(tree[k].l==tree[k].r) {if(mx<=tree[k].mmax) {int ans=tree[k].flag!=pre;mx=tree[k].mmax,pre=tree[k].flag;return ans;} else return 0;}pushdown(k);if(mx>tree[k<<1].mmax) return cal(k<<1|1,mx,pre);else {int ans=cal(k<<1,mx,pre)+tree[k].cnt-tree[k<<1].cnt;mx=tree[k].mmax,pre=tree[k].flag;return ans;} } void pushup(int k) {if(tree[k<<1].mmax>tree[k<<1|1].mmax) {tree[k].mmax=tree[k<<1].mmax,tree[k].flag=tree[k<<1].flag;} else {tree[k].mmax=tree[k<<1|1].mmax,tree[k].flag=tree[k<<1|1].flag;}int mx=tree[k<<1].mmax,pre=tree[k<<1].flag;tree[k].cnt=tree[k<<1].cnt+cal(k<<1|1,mx,pre); } void build(int k,int l,int r) {tree[k]={l,r,0,0,0,0};if(l==r) {tree[k].mmax=a[l],tree[k].flag=b[l];return;}int mid=(l+r)>>1;build(k<<1,l,mid),build(k<<1|1,mid+1,r);pushup(k); } void update_a(int k,int pos,int val) {if(tree[k].l==tree[k].r) {tree[k].mmax=val;return;}pushdown(k);int mid=(tree[k].l+tree[k].r)>>1;if(pos<=mid) update_a(k<<1,pos,val);else update_a(k<<1|1,pos,val);pushup(k); } void update_b(int k,int l,int r) {if(tree[k].l>r||tree[k].r<l) return;if(tree[k].l>=l&&tree[k].r<=r) {tree[k].flag^=1,tree[k].lazy^=1;return;}pushdown(k);update_b(k<<1,l,r),update_b(k<<1|1,l,r);pushup(k); } int query_ans(int k,int l,int r,int &mx,int &pre) {if(tree[k].l>r||tree[k].r<l) return 0;if(tree[k].l>=l&&tree[k].r<=r) {if(mx<=tree[k].mmax) return cal(k,mx,pre);else return 0;}pushdown(k);return query_ans(k<<1,l,r,mx,pre)+query_ans(k<<1|1,l,r,mx,pre); } int query_a(int k,int pos) {if(tree[k].l==tree[k].r) return tree[k].mmax;pushdown(k);int mid=(tree[k].l+tree[k].r)>>1;if(pos<=mid) return query_a(k<<1,pos);else return query_a(k<<1|1,pos); } int query_b(int k,int pos) {if(tree[k].l==tree[k].r) return tree[k].flag;pushdown(k);int mid=(tree[k].l+tree[k].r)>>1;if(pos<=mid) return query_b(k<<1,pos);else return query_b(k<<1|1,pos); } int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int n,m;read(n);for(int i=1;i<=n;i++) read(a[i]);for(int i=1;i<=n;i++) read(b[i]);build(1,1,n);read(m);while(m--) {int op,x,y;read(op),read(x),read(y);if(op==1) update_a(1,x,y);else if(op==2) update_b(1,x,y);else if(op==3) {int mx=query_a(1,x),pre=query_b(1,x);cout<<query_ans(1,x,y,mx,pre)<<endl;}}return 0; }總結(jié)
以上是生活随笔為你收集整理的2021牛客多校7 - xay loves monotonicity(线段树区间合并)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 洛谷 - P3321 [SDOI2015
- 下一篇: 2021HDU多校7 - 7054 Yi