[树上莫队]JZOJ 3360 苹果树
分析
题拿到手
第一秒:又链剖?
两分钟后:树上莫队
然鹅并没有学,打了个链剖拿mutliset维护颜色集合结果没对拍爆零了(貌似可以水到20)
新学的东西会写学习笔记解析的,这里不做赘述(毕竟算个模板题)
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; const int N=5e4+10; struct Graph { int v,nx; }g[2*N]; int cnt,list[N]; struct Task { int x,y,l,r,lca,id,c1,c2; }t[2*N]; int l[N],r[N],f[N][20],dep[N],id[2*N],ans[2*N],c[N],a[N],q[2*N]; bool in[N]; int n,m,mlen,tme,num; void Add(int u,int v) { g[++cnt]=(Graph){v,list[u]};list[u]=cnt; g[++cnt]=(Graph){u,list[v]};list[v]=cnt; } void DFS(int u,int fa) { dep[u]=dep[fa]+1;f[u][0]=fa;q[l[u]=++tme]=u; for (int i=list[u];i;i=g[i].nx) if (g[i].v!=fa) DFS(g[i].v,u); q[r[u]=++tme]=u; } int LCA(int x,int y) { if (dep[x]<dep[y]) swap(x,y); for (int i=19;i>=0;i--) if (dep[f[x][i]]>=dep[y]) x=f[x][i]; if (x==y) return x; for (int i=19;i>=0;i--) if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } bool CMP(Task a,Task b) { return id[a.l]<id[b.l]||id[a.l]==id[b.l]&&((id[a.l]&1)?a.r<b.r:a.r>b.r); } void Deal(int x) { in[x]^=1; if (in[x]) { if (!c[a[x]]) num++; c[a[x]]++; } else { c[a[x]]--; if (!c[a[x]]) num--; } } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&a[i]); for (int i=1,u,v;i<=n;i++) { scanf("%d%d",&u,&v); if (u&&v) Add(u,v); } DFS(1,0); for (int j=1;j<20;j++) for (int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; for (int i=1;i<=m;i++) { scanf("%d%d%d%d",&t[i].x,&t[i].y,&t[i].c1,&t[i].c2);t[i].id=i; if (l[t[i].x]>l[t[i].y]) swap(t[i].x,t[i].y); if (l[t[i].y]<=r[t[i].x]) t[i].l=l[t[i].x],t[i].r=l[t[i].y],t[i].lca=0; else t[i].l=r[t[i].x],t[i].r=l[t[i].y],t[i].lca=1; } mlen=sqrt(tme); for (int i=1;i<=tme;i++) id[i]=i/mlen+(i%mlen!=0); sort(t+1,t+m+1,CMP); int l=1,r=1;Deal(q[1]); for (int i=1;i<=m;i++) { while (l<t[i].l) Deal(q[l++]);while (l>t[i].l) Deal(q[--l]); while (r<t[i].r) Deal(q[++r]);while (r>t[i].r) Deal(q[r--]); int lca=LCA(t[i].x,t[i].y); if (t[i].lca) Deal(lca); ans[t[i].id]=num; if (t[i].c1!=t[i].c2&&c[t[i].c1]&&c[t[i].c2]) ans[t[i].id]--; if (t[i].lca) Deal(lca); } for (int i=1;i<=m;i++) printf("%d\n",ans[i]); }
在日渐沉没的世界里,我发现了你。