樹上莫隊共有三種寫法:
1.按dfs序列分塊,和普通莫隊類似。常數大,不會被卡。
2.按塊狀樹的方式分塊。常數小,會被菊花圖卡到o(n)。
3.按[bzoj1086]王室聯邦的方式分塊。常數小,不會被卡。唯一的缺點是較抽象,乙個塊可能是不連通的。
權衡一下當然還是寫第三種做法,具體看**。
然後還有乙個問題,手動模擬莫隊移動左右端點指標的過程,會發現lca處較難處理,它常常是跟其它點反著的。於是我們每次移指標的時候都忽略lca,最後詢問的時候加上lca求解答案再減去lca。再模擬會發現,所有方案都可以處理了。
以及要注意每個詢問如果左端點所在塊編號比右端點所在塊大則需要交換左右端點。詢問的排序方式是:若兩端點不在同一塊則按塊編號排序,否則按dfs序排序。也就是按(bel[i],dfn[i])的雙關鍵字排序。
1 #include2 #include3 #include4#define rep(i,l,r) for (int i=(l); i<=(r); i++)
5#define for(i,x) for (int i=h[x],k; i; i=nxt[i])
6using
namespace
std;78
const
int n=200010;9
int n,m,b,u,v,tim,top,tot,a[n],stk[n],b[n],dep[n],fa[n][20
];10
intcnt,res,rt,vis[n],ans[n],dfn[n],s[n],h[n],to[n],nxt[n];
11struct pq[n];
1213
bool cmp(const p &x,const p &y)
14void add(int u,int v)
1516
void dfs(int
x)22
}23 stk[++top]=x;24}
2526
int lca(int x,int
y)34
35void upd(int
x)37
else
38 vis[x]^=1;39
}4041void work(int x,int
y)45
46int
main()
54add(u,v); add(v,u);55}
56dfs(rt);
57while (top) b[stk[top--]]=tot;
58 rep(i,1
,m)62 sort(q+1,q+m+1
,cmp);
63int l=rt,r=rt;
64 rep(i,1
,m)69 rep(i,1,m) printf("
%d\n
",ans[i]);
70return0;
71 }
BZOJ 3757 蘋果樹 樹上莫隊
題目大意 給定一棵樹,每個節點有乙個顏色,多次求兩個節點的路徑上有多少種不同的顏色 其中還有兩個引數a和b,若蘋果樹上同時有這兩種顏色,ans 傳說中的樹上莫隊 顏色數既不滿足區間加法也不滿足區間減法,直接維護極其困難,這種東西就直接考慮莫隊好了 但是怎麼轉移是個問題 首先樹分塊 然後以左端點所在塊...
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 蘋果樹(樹上莫隊)
點此看題面 大致題意 每次問你樹上兩點之間路徑中有多少種顏色,每次詢問可能會將一種顏色 a 看成 b 這題是一道樹上莫隊板子題。畢竟求區間中有多少種不同的數是莫隊演算法的經典應用啊。這操作其實很好處理。只要判斷 cnt a 和 cnt b 是否同時 0 即可。但要注意特判 a b 的情況。inclu...