BZOJ 3757 蘋果樹 樹上莫隊

2021-06-27 05:55:27 字數 1343 閱讀 2874

題目大意:給定一棵樹,每個節點有乙個顏色,多次求兩個節點的路徑上有多少種不同的顏色 其中還有兩個引數a和b,若蘋果樹上同時有這兩種顏色,ans--

傳說中的樹上莫隊……顏色數既不滿足區間加法也不滿足區間減法,直接維護極其困難,這種東西就直接考慮莫隊好了

但是怎麼轉移是個問題

首先樹分塊 然後以左端點所在塊為第一鍵值,右端點在dfs序中的位置為第二鍵值排序 (優化:若左端點在dfs序中的位置大於右端點的位置,則交換左右端點)

對於每個點我們記錄乙個狀態,表示當前是否加入答案中統計

初始兩個端點指向同一位置,狀態全為空。然後對於每個詢問我們做如下處理

設當前左右端點為x,y,當前詢問的左右端點為qx,qy

將x到qx路徑上除lca(x,qx)之外的點狀態反轉

將y到qy路徑上除lca(y,qy)之外的點狀態反轉

將lca(qx,qy)狀態反轉

統計當前詢問的答案

將lca(qx,qy)狀態反轉

保證每次詢問後,加入答案的點集為(qx,qy)路徑上除lca(qx,qy)之外的點

證明詳見vfleaking的部落格 

記住如果tle不一定是常數大或者死迴圈 可能是莫隊寫掛了

#include #include #include #include #include #define m 50500

using namespace std;

namespace iostream

return *s++;

}int get_int()

}struct queryq[m<<1];

struct abcdtable[m<<1];

int head[m],tot;

int n,m,block,root;

int a[m],belong[m],pos[m],size[m],dpt[m],fa[m][20];

int cnt[m],now,ans[m<<1],l,r;

bool v[m];

bool query :: operator < (const query &y) const

int main()

dfs(root,0);

for(j=1;j<=15;j++)

for(i=1;i<=n;i++)

fa[i][j]=fa[fa[i][j-1]][j-1];

for(i=1;i<=m;i++)

sort(q+1,q+m+1);

l=r=root;

for(i=1;i<=m;i++)

for(i=1;i<=m;i++)

printf("%d\n",ans[i]);

}

bzoj3757 蘋果樹 樹上莫隊

題目大意 給定一棵n nn個節點的樹,每個節點有乙個顏色a ia i ai 有m mm個詢問,每次給出u,v a,b u,v,a,b u,v,a,b,表示u uu到v vv的路徑上,把所有顏色a aa看成顏色b bb,求出有多少種顏色。詢問不會修改節點真實的顏色。n 50000.n 50000.n ...

BZOJ3757 蘋果樹 樹上莫隊

樹上莫隊共有三種寫法 1.按dfs序列分塊,和普通莫隊類似。常數大,不會被卡。2.按塊狀樹的方式分塊。常數小,會被菊花圖卡到o n 3.按 bzoj1086 王室聯邦的方式分塊。常數小,不會被卡。唯一的缺點是較抽象,乙個塊可能是不連通的。權衡一下當然還是寫第三種做法,具體看 然後還有乙個問題,手動模...

BZOJ3757 蘋果樹(樹上莫隊)

點此看題面 大致題意 每次問你樹上兩點之間路徑中有多少種顏色,每次詢問可能會將一種顏色 a 看成 b 這題是一道樹上莫隊板子題。畢竟求區間中有多少種不同的數是莫隊演算法的經典應用啊。這操作其實很好處理。只要判斷 cnt a 和 cnt b 是否同時 0 即可。但要注意特判 a b 的情況。inclu...