F. Flip (2021 ICPC Asia Taiwan)
阿新 • • 發佈:2021-11-04
namo,第一篇這裡的部落格來記錄下我的愚蠢吧qaq
本題題意:
給定由0、1組成的陣列a,要求支援兩種操作,opt1:對於i∈[l,r],a[i] = 1 - a[i]; opt2:查詢區間”美麗“序列的pair對數。(定義一個序列美麗為:如果當前序列是1 0 1 0 1 0 1 0 …… 的某個子串,即該序列是美麗的;eg : [1]、[0]、[1,0,1]都是美麗的序列,而[1,1]、[1,0,0]則不是美麗序列)
思路:
”當你想不到線段樹該維護什麼的時候,不妨就先設想直接維護答案,再看看答案由什麼可以得來的思路來解決問題“---P500
namo,操作一加個區間反轉的tag即可解決,操作二的話我們可以設想直接維護答案ans,那現在就是考慮pushup操作如何利用左兒子區間和右兒子區間的資訊維護當前結點區間的資訊,容易發現當左兒子的右端點 == 右兒子的左端點時,root.ans = lson.ans + rson.ans; else的話,則會產生額外的貢獻,首先一個連續01串會產生的貢獻是len * (len+1) / 2,合併後產生的新貢獻即為:(l+r) * (l+r+1) /2 - [ l* (l+1) / 2 + r * (r+1) / 2 ],恰好等於 l * r,那麼l和r分別是區間從左開始以及從右開始最長的01交替序列長度,另外還需要維護區間最左邊和最右邊分別是0還是1,所以線段樹需要多維護這兩個資訊,下面附上程式碼。
點選檢視程式碼
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops") #pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,abm,mmx,avx,avx2,popcnt,tune=native") #pragma GCC target ("avx2,fma") #pragma GCC optimize ("O3") #pragma GCC optimize ("unroll-loops") #include<bits/stdc++.h> #include <ext/rope> using namespace __gnu_cxx; #define int long long #define endl '\n' using namespace std; int IOS = []() {ios::sync_with_stdio(0); std::cin.tie(nullptr); std::cout.tie(nullptr); return 0; }(); const int N = 2e5+10; int a[N]; struct node{ int l,r; bool tag; bool lv,rv; //最左、右的值 int ans; int lenl,lenr; // 交替序列長度 }tr[N*4]; node pushup(node &ro,node &L,node &R) { ro.l = L.l; ro.r = R.r; ro.lv = L.lv; ro.rv = R.rv; ro.tag = 0; if(L.rv==R.lv) { ro.lenl = L.lenl; ro.lenr = R.lenr; ro.ans = L.ans + R.ans; return ro; } ro.lenl = (L.lenl == L.r-L.l+1) ? L.lenl + R.lenl : L.lenl; ro.lenr = (R.lenr == R.r-R.l+1) ? R.lenr + L.lenr : R.lenr; ro.ans = L.ans + R.ans + L.lenr * R.lenl; return ro; } void pushup(int u) { pushup(tr[u],tr[u<<1],tr[u<<1|1]); } void pushdown(int u) { if(tr[u].tag) { tr[u<<1].lv ^= 1; tr[u<<1].rv ^= 1; tr[u<<1|1].lv ^= 1; tr[u<<1|1].rv ^= 1; tr[u<<1].tag ^= 1; tr[u<<1|1].tag ^= 1; tr[u].tag = 0; } } void build(int u,int l,int r) { tr[u] = {l,r}; if(l==r) { tr[u].lv = tr[u].rv = a[l]; tr[u].ans = tr[u].lenl = tr[u].lenr = 1; return; } int mid = l + r >>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); pushup(u); } void update(int u,int l,int r) { if(tr[u].l>=l&&tr[u].r<=r) { tr[u].lv ^= 1; tr[u].rv ^= 1; tr[u].tag ^= 1; return; } int mid = tr[u].l + tr[u].r >>1; pushdown(u); if(l<=mid) update(u<<1,l,r); if(r>mid) update(u<<1|1,l,r); pushup(u); } node query(int u,int l,int r) { if(tr[u].l>=l&&tr[u].r<=r) return tr[u]; int mid = tr[u].l + tr[u].r >>1; pushdown(u); if(r<=mid) return query(u<<1,l,r); else if(l>mid) return query(u<<1|1,l,r); else { node ro,L = query(u<<1,l,r),R = query(u<<1|1,l,r); pushup(ro,L,R); return ro; } } void solve() { int n,q; cin>>n>>q; for(int i=1;i<=n;i++) cin>>a[i]; build(1,1,n); while(q--) { int opt,l,r; cin>>opt>>l>>r; if(opt==1) update(1,l,r); else cout<<query(1,l,r).ans<<endl; } } signed main() { int tt = 1; while(tt--) { solve(); } }