SP10707 COT2 - Count on a tree II
生活随笔
收集整理的這篇文章主要介紹了
SP10707 COT2 - Count on a tree II
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
SP10707 COT2 - Count on a tree II
題意:
給定 n 個結點的樹,每個結點有一種顏色。
m 次詢問,每次詢問給出 u,v,回答 u,v 之間的路徑上的結點的不同顏色數。
1< = n < =4*10^4
1< = m < =10^5
題解:
樹上莫隊的裸題
但是裸題也是很難。。emm
我這里有比較詳細的講解
我大體總結一下就是:歐拉序實現樹轉為線性結構,然后在上面跑莫隊
當然還要考慮v是u的子樹,u和v不在一個子樹等等各種情況
lca可以用樹剖求,也可以lca
詳細看代碼
代碼:
代碼不是自己打的,等我把樹剖復習完再重新打一遍
#include <iostream> #include <algorithm> #include <cstdio> #include <cmath> #include <vector> #define N 200000 using namespace std; struct node {int l,r,ll,rr,id,lca; }q[N+5]; int n,m,a[N+5],st[N+5],ed[N+5],dfn[N+5],f[N+5],num,size[N+5],his[N+5],dep[N+5],son[N+5],top[N+5],c[N+5],tmp,block,l=1,r,use[N+5],ans[N+5],data[N+5]; vector <int> d[N+5]; void dfs1(int u,int fa) //樹剖第一次深搜 {f[u]=fa;st[u]=++num;size[u]=1;his[num]=u;dep[u]=dep[fa]+1;vector <int>::iterator it;for (it=d[u].begin();it!=d[u].end();it++){int v=(*it);if (v==fa)continue;dfs1(v,u);size[u]+=size[v];if (size[v]>size[son[u]])son[u]=v;}ed[u]=++num;his[num]=u; } void dfs2(int u,int to) //樹剖第二次深搜 {top[u]=to;if (son[u])dfs2(son[u],to);vector <int>::iterator it;for (it=d[u].begin();it!=d[u].end();it++){int v=(*it);if (v!=son[u]&&v!=f[u])dfs2(v,v);} } int Lca(int x,int y) //樹剖求lca {while (top[x]!=top[y]){if (dep[top[x]]<dep[top[y]])swap(x,y);x=f[top[x]];}if (dep[x]>dep[y])swap(x,y);return x; } void add(int x) {tmp+=(++c[a[x]]==1); } void del(int x) {tmp-=(--c[a[x]]==0); } void calc(int x) //對點進行加入或刪除 {(use[x]==0)?add(x):del(x);use[x]^=1; } int cmp(node x,node y) //排序 {return (x.ll==y.ll)?(x.ll%2==1?x.r<y.r:x.r>y.r):x.l<y.l; } int main() {scanf("%d%d",&n,&m);for (int i=1;i<=n;i++)scanf("%d",&a[i]),data[i]=a[i];sort(data+1,data+n+1);for(int i=1;i<=n;i++)a[i]=lower_bound(data+1,data+n+1,a[i])-data; //離散化int x,y;for (int i=1;i<n;i++){scanf("%d%d",&x,&y);d[x].push_back(y);d[y].push_back(x);}dfs1(1,0); dfs2(1,1);block=n*2/sqrt(m*2/3);for (int i=1;i<=m;i++){scanf("%d%d",&x,&y);if (st[x]>st[y])swap(x,y); //保證stx<styq[i].id=i;q[i].lca=Lca(x,y); if (q[i].lca==x) //x,y在以x為根的子樹中{q[i].l=st[x];q[i].r=st[y];q[i].ll=st[x]/block;q[i].rr=st[y]/block;q[i].lca=0;}else{q[i].l=ed[x];q[i].r=st[y];q[i].ll=ed[x]/block;q[i].rr=st[y]/block;}}sort(q+1,q+m+1,cmp);for (int i=1;i<=m;i++){while (l>q[i].l)calc(his[--l]);while (r<q[i].r)calc(his[++r]);while (l<q[i].l)calc(his[l++]);while (r>q[i].r)calc(his[r--]);if (q[i].lca)calc(q[i].lca);ans[q[i].id]=tmp;if (q[i].lca)calc(q[i].lca);}for (int i=1;i<=m;i++)printf("%d\n",ans[i]);return 0; }總結
以上是生活随笔為你收集整理的SP10707 COT2 - Count on a tree II的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 酵母的功效与作用、禁忌和食用方法
- 下一篇: [CQOI2018]异或序列