\(question\)
題目大意:給乙個顏色序列,待修改,求區間顏色段數。
\(solution\)
考慮線段樹合併。
對於每乙個顏色建乙個線段樹,維護每個顏色出現的位置。同時維護區間的顏色段數,以及最左端、最右端的顏色位置。
於是,對於合併顏色\(x,y\).,·將它們對應線段樹合併即可。合併時,當一樹為空時,直接返回;當遞迴到葉子時,左右均為該處\(pos\).顏色段為1,返回即可。
對於插入時,與合併處理邊界一樣。
維護資訊時,左端資訊優先考慮左子樹,右端資訊優先考慮右子樹,總資訊將左右顏色段相加,但若兩端相交處顏色相同,則需要-1.
修改時一同維護\(ans.\)即可。
(蒟蒻第一次寫非權值線段樹的線段樹合併)
\(\text\)
#includeusing namespace std;
#define int long long
const int maxn=1e6+10;
int n,m,ans;
int rt[maxn],ch[maxn<<5][2],rub[maxn<<5],tot,cnt;
int a[maxn],ls[maxn<<5],rs[maxn<<5],ms[maxn<<5];
inline int build()
inline void del(int x)
inline void pushup(int x)
void modify(int &p,int l,int r,int pos)
int mid=l+r>>1;
if(pos<=mid)modify(ch[p][0],l,mid,pos);
else modify(ch[p][1],mid+1,r,pos);
pushup(p);
}int merge(int x,int y,int l,int r)
if(l==r)
int mid=l+r>>1;
ch[x][0]=merge(ch[x][0],ch[y][0],l,mid);
ch[x][1]=merge(ch[x][1],ch[y][1],mid+1,r);
del(y);pushup(x);return x;
}inline void solve()
void change(int x,int y)
signed main()
int q=m;
for(;q;q--)
} return 0;
}
HNOI2009 夢幻布丁
題意 n個布丁擺成一行,進行m次操作.每次將某個顏色的布丁全部變成另一種顏色的,然後再詢問當前一共有多少段顏色.例如顏色分別為1,2,2,1的四個布丁一共有3段顏色.對每個顏色的位置維護鍊錶。合併兩個顏色,連線鍊錶,統計貢獻。統計貢獻的複雜度是與鍊錶長度有關的。如果遍歷長度短的鍊錶那麼複雜度自然更小...
HNOI2009 夢幻布丁
n個布丁擺成一行,進行m次操作.每次將某個顏色的布丁全部變成另一種顏色的,然後再詢問當前一共有多少段顏色.例如顏色分別為1,2,2,1的四個布丁一共有3段顏色.輸入格式 第一行給出n,m表示布丁的個數和好友的操作次數.第二行n個數a1,a2.an表示第i個布丁的顏色從第三行起有m行,對於每個操作,若...
HNOI2009 夢幻布丁
題目鏈結 把每一種數字想象成乙個佇列。如果暴力合併,時間複雜度必然很高,考慮啟發式合併 每次把數字少的佇列合併到數字多的佇列上去。每次合併,若數字少的佇列數字個數為 s 則合併之後產生新佇列的大小必定不小於 2 s 時間複雜度 o n log n 這樣合併產生了乙個問題 即原來要求將 a 全部變為 ...