當前位置:
首頁 >
jzoj3360-[NOI2013模拟]苹果树【树上莫队,LCA】
發布時間:2023/12/3
28
豆豆
生活随笔
收集整理的這篇文章主要介紹了
jzoj3360-[NOI2013模拟]苹果树【树上莫队,LCA】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
題目大意
一棵樹上每個節點有不同的顏色,然后每次詢問(x,y,a,b)(x,y,a,b)(x,y,a,b)表示將顏色aaa看為顏色bbb的情況下詢問xxx到yyy有多少不種的顏色。
解題思路
數顏色,顯然樹上莫隊。我們維護一個歐拉序dfndfndfn(進去時記錄一次出來時記錄一次),然后rfnirfn_irfni?表示點iii進入時在dfndfndfn中的位置,rgnirgn_irgni?表示點iii在出去時在iii的位置。
然后每次移動端點時,只有在[l,r][l,r][l,r]這個區間中出現一次的點的顏色才會被記錄入cntcntcnt(讓出現兩次的相互抵消)。那么我們就可以讓x,yx,yx,y所在它的LCALCALCA的子樹中這個序列,讓他們中間的相互抵消。
不過要注意,若x,yx,yx,y不是他們的LCALCALCA,那么他們的LCALCALCA就被計算了兩次,就重復了,統計答案時要減去重復的。
codecodecode
#include<cstdio> #include<algorithm> #include<queue> #include<cmath> using namespace std; const int N=51000,M=110000; struct line{int to,next,w; }a[M]; struct Que_node{int l,r,a,b,id,pos; }que[M]; bool operator<(Que_node x,Que_node y) {return x.pos==y.pos?x.r<y.r:x.pos<y.pos;} int n,m,c[N],dfn[M],rfn[N],rgn[N],v[N],cnt,num,ans[N]; int tot,x,y,ls[N],dep[N],f[N][30],t,T; bool b[N]; queue<int> q; inline int read() {int X=0,w=0; char c=0;while(c<'0'||c>'9') {w|=c=='-';c=getchar();}while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();return w?-X:X; } inline void addl(int x,int y,int w) {a[++tot].to=y;a[tot].next=ls[x];a[tot].w=w;ls[x]=tot; } void dfs(int x,int fa) {dfn[++cnt]=x;rfn[x]=cnt;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa) continue;dfs(y,x);}dfn[++cnt]=x;rgn[x]=cnt; } inline void bfs(int s) {q.push(s);dep[s]=1;while(!q.empty()){int x=q.front();q.pop();for (int i=ls[x];i;i=a[i].next){int y=a[i].to;if (dep[y]) continue;q.push(y);f[y][0]=x;dep[y]=dep[x]+1;}}T=(int)(log(n)/log(2))+1;for (int j=1;j<=T;j++)for (int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1]; } inline int LCA(int x,int y) {if (dep[x]>dep[y]) swap(x,y);for (int i=T;i>=0;i--)if (dep[f[y][i]]>=dep[x]) y=f[y][i];if (x==y) return x;for (int i=T;i>=0;i--)if (f[y][i]!=f[x][i]) {x=f[x][i];y=f[y][i];}return f[x][0]; } void rev(int x) {if(b[x]) v[c[x]]--,num-=(v[c[x]]==0);else num+=(v[c[x]]==0),v[c[x]]++;b[x]^=1; } void Keep_zzy(int &l,int &r,int L,int R) {while(l<L) rev(dfn[l]),l++;while(l>L) l--,rev(dfn[l]);while(r<R) r++,rev(dfn[r]);while(r>R) rev(dfn[r]),r--; } int main() {freopen("apple.in","r",stdin);freopen("apple.out","w",stdout);n=read();m=read();for(int i=1;i<=n;i++)c[i]=read();for(int i=1;i<=n;i++){addl(x=read(),y=read(),1);addl(y,x,1);}dfs(0,0);bfs(0);t=(int)sqrt((double)cnt);for(int i=1;i<=m;i++){scanf("%d%d%d%d",&que[i].l,&que[i].r,&que[i].a,&que[i].b);if(rfn[que[i].l]>rfn[que[i].r])swap(que[i].l,que[i].r);que[i].l=rgn[que[i].l];que[i].r=rfn[que[i].r];if(que[i].l>=que[i].r) que[i].l=rfn[dfn[que[i].l]];que[i].id=i;que[i].pos=(que[i].l-1)/t+1;}sort(que+1,que+1+m);int l=1,r=0;v[0]=1; for(int i=1;i<=m;i++){int x=que[i].l,y=que[i].r;Keep_zzy(l,r,x,y);int lca=LCA(dfn[x],dfn[y]);bool flag=0;if(dfn[x]!=lca&&dfn[y]!=lca)rev(lca),flag=1;ans[que[i].id]=num;if(v[que[i].a]&&v[que[i].b]&&que[i].a!=que[i].b)ans[que[i].id]--;if(flag) rev(lca);}for(int i=1;i<=m;i++)printf("%d\n",ans[i]); }總結
以上是生活随笔為你收集整理的jzoj3360-[NOI2013模拟]苹果树【树上莫队,LCA】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jzoj1166-树中点对距离【点分治】
- 下一篇: 冰冻三尺是什么意思 词语冰冻三尺是什么意