HDU5709 : Claris Loves Painting
生活随笔
收集整理的這篇文章主要介紹了
HDU5709 : Claris Loves Painting
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
對于每個點維護兩棵線段樹$T1[x],T2[x]$:
$T1[x]$維護$x$子樹內,深度在$[l,r]$內的點數,同種顏色有多個的話,保留深度最小的那個。
$T2[x]$維護$x$子樹內每種顏色的最小深度。
從底向上合并線段樹,先合并$T1$,然后合并$T2$的時候,發現有重復點,那么在$T1$里刪去深度大的那個,查詢直接在$T1$里區間求和即可。
時間復雜度$O((n+m)\log n)$。
?
#include<cstdio> const int N=100010,M=10000000; int Case,n,m,i,x,y,ans,a[N],f[N],d[N],T1[N],T2[N],tot,l[M],r[M],v[M]; int ins(int x,int a,int b,int c,int p){int y=++tot;v[y]=v[x]+p;if(a==b)return y;int mid=(a+b)>>1;if(c<=mid)l[y]=ins(l[x],a,mid,c,p),r[y]=r[x];else l[y]=l[x],r[y]=ins(r[x],mid+1,b,c,p);return y; } int merge1(int x,int y,int a,int b){if(!x||!y)return x+y;int z=++tot;v[z]=v[x]+v[y];if(a==b)return z;int mid=(a+b)>>1;l[z]=merge1(l[x],l[y],a,mid);r[z]=merge1(r[x],r[y],mid+1,b);return z; } int merge2(int x,int y,int a,int b,int p){if(!x||!y)return x+y;int z=++tot;if(a==b){if(v[x]<v[y])v[z]=v[x],T1[p]=ins(T1[p],1,n,v[y],-1);else v[z]=v[y],T1[p]=ins(T1[p],1,n,v[x],-1);return z;}int mid=(a+b)>>1;l[z]=merge2(l[x],l[y],a,mid,p);r[z]=merge2(r[x],r[y],mid+1,b,p);return z; } int ask(int x,int a,int b,int d){if(b<=d)return v[x];int mid=(a+b)>>1,t=ask(l[x],a,mid,d);if(d>mid)t+=ask(r[x],mid+1,b,d);return t; } int main(){scanf("%d",&Case);while(Case--){scanf("%d%d",&n,&m);for(i=1;i<=n;i++)scanf("%d",&a[i]);for(i=2;i<=n;i++)scanf("%d",&f[i]);for(i=1;i<=n;i++)d[i]=d[f[i]]+1;for(i=1;i<=n;i++){T1[i]=ins(0,1,n,d[i],1);T2[i]=ins(0,1,n,a[i],d[i]);}for(i=n;i>1;i--){T1[f[i]]=merge1(T1[f[i]],T1[i],1,n);T2[f[i]]=merge2(T2[f[i]],T2[i],1,n,f[i]);}while(m--){scanf("%d%d",&x,&y);x^=ans,y^=ans;y+=d[x];if(y>n)y=n;printf("%d\n",ans=ask(T1[x],1,n,y));}ans=tot=0;}return 0; }
總結
以上是生活随笔為你收集整理的HDU5709 : Claris Loves Painting的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 技术网站 --入门无忧网
- 下一篇: thinkphp集成系列之phpmail