给定一个多边形的三角剖分(n<=1e5),且每个三角形有其颜色,问最多可以把这个三角剖分分成几个联通的部分,使任何一种颜色不出现在多个连通块中
建出三角剖分对应的树,同种颜色的点之间的路径是不能被切开的,因此将同色的点间路径标记一下,未标记的边数即为答案
具体实现可以用树上差分进行标记,树链剖分lca,同色的点按dfs序排序并将排序后相邻的点间路径标记
#include<cstdio> #include<algorithm> typedef long long i64; const int R=5e6,N=100007,P=1844677; char buf[R],*ptr=buf-1; int _(){ int x=0,c=*++ptr; while(c<48)c=*++ptr; while(c>47)x=x*10+c-48,c=*++ptr; return x; } long long hx[P]; int hy[P]; int n,ans=-1; int e[N][3],ep[N],col[N],cc[N],*cl[N],*cr[N],_c[N],*cp=_c,v[N]; int fa[N],sz[N],son[N],dep[N],top[N],id[N],idp=0; void chk(int a,int b,int id){ if(a>b)std::swap(a,b); i64 h=i64(a)<<20|b; int w=h%P; while(hy[w]){ if(hx[w]==h){ e[hy[w]][ep[hy[w]]++]=id; e[id][ep[id]++]=hy[w]; return; } if((w+=12347)>=P)w-=P; } hx[w]=h;hy[w]=id; } void f1(int w,int pa){ fa[w]=pa; dep[w]=dep[pa]+1; sz[w]=1; for(int i=0;i<ep[w];++i){ int u=e[w][i]; if(u==pa)continue; f1(u,w); sz[w]+=sz[u]; if(sz[son[w]]<sz[u])son[w]=u; } } void f2(int w,int tp){ top[w]=tp; id[w]=++idp; if(son[w])f2(son[w],tp); for(int i=0;i<ep[w];++i){ int u=e[w][i]; if(u==fa[w]||u==son[w])continue; f2(u,u); } } void f3(int w){ for(int i=0;i<ep[w];++i){ int u=e[w][i]; if(u==fa[w])continue; f3(u); v[w]+=v[u]; } if(!v[w])++ans; } int lca(int x,int y){ int a=top[x],b=top[y]; while(a!=b){ if(dep[a]<dep[b])std::swap(a,b),std::swap(x,y); x=fa[a];a=top[x]; } return dep[x]<dep[y]?x:y; } bool cmp(int a,int b){ return id[a]<id[b]; } int main(){ fread(buf,1,R,stdin); n=_()-2; for(int i=1;i<=n;++i){ int a=_(),b=_(),c=_(); chk(a,b,i); chk(a,c,i); chk(c,b,i); ++cc[col[i]=_()]; } for(int i=1;i<=n;++i)cl[i]=cr[i]=cp,cp+=cc[i]; for(int i=1;i<=n;++i)*(cr[col[i]]++)=i; f1(1,0); f2(1,1); for(int i=1;i<=n;++i)if(cl[i]!=cr[i]){ std::sort(cl[i],cr[i],cmp); for(int p=1;p<cc[i];++p){ int x=cl[i][p],y=cl[i][p-1],z=lca(x,y); ++v[x];++v[y];v[z]-=2; } } f3(1); printf("%d",ans); return 0; }