题解 P5168 【xtq玩魔塔】

mrsrz

2019-06-27 20:25:19

Solution

随机数据也太毒了吧,假算法放过去一大堆,这题明明有一个$\log$的算法的啊……~~有本事数据范围加个0~~ 首先考虑第二个询问,这个询问和[ \[NOI2018\] 归程](https://www.luogu.org/problemnew/show/P4768)类似,可以使用克鲁斯卡尔重构树解决。 然后考虑第三个询问,把它放在重构树上,就是一个子树数颜色问题。由于有修改操作,所以就是个带修子树数颜色问题。 这个是可以一个$\log$解决的。~~不知道为什么要放带修莫队和树套树过去而且还跑那么快~~ 显然可以用树状数组维护子树信息(dfs序连续)。 我们考虑每加入一个节点$x$的时候,在哪些节点处能产生贡献。显然,能产生贡献的节点所在子树内原本没有这种颜色。 我们可以找到这种颜色的一个其他节点$y$,使它与$x$的$\rm LCA$的深度最深。那么$x$能在该节点到$\rm{LCA}$(不包含$\rm{LCA}$)的路径上各产生1的贡献。 用差分的思想,在树状数组上,$x$处加1,在$\rm{LCA}$处减1即可。 而这样的$y$,只可能是dfs序和$x$最相近的两个中的一个(比它小和比它大,也可能只有一个),用```set```维护一下即可。 然后查询颜色就直接查询树状数组上这棵子树即可。 这样就做到一个$\log$维护颜色信息了。 于是总时间复杂度$O((n+m+q)\log n)$。 ## Code: ```cpp #include<cstdio> #include<cctype> #include<algorithm> #include<set> #include<vector> using namespace std; vector<int>vec; inline int readint(){ int c=getchar(),d=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar())d=d*10+(c^'0'); return d; } const int N=4e5+5; int ff[N],n,m,col[N],Q; inline int find(int x){return x==ff[x]?x:ff[x]=find(ff[x]);} struct que{ int op,x,y; }q[N]; namespace nt{ int to[N],nxt[N],head[N],cnt,fa[N],dw[N],rt,dep[N],F[18][N],idfn[N]; int sz[N],son[N],top[N],dfn[N],idx; inline void addedge(int u,int v,int w){to[++cnt]=v,nxt[cnt]=head[u],head[u]=cnt,fa[v]=u,dw[u]=w;} void dfs(int now){ sz[now]=1,son[now]=0; for(int i=head[now];i;i=nxt[i]){ dep[to[i]]=dep[now]+1,F[0][to[i]]=now,dfs(to[i]),sz[now]+=sz[to[i]]; if(!son[now]||sz[son[now]]<sz[to[i]])son[now]=to[i]; } } void dfs2(int now){ idfn[dfn[now]=++idx]=now; if(son[now])top[son[now]]=top[now],dfs2(son[now]); for(int i=head[now];i;i=nxt[i])if(to[i]!=son[now])dfs2(top[to[i]]=to[i]); } inline int LCA(int x,int y){ while(top[x]!=top[y]) if(dep[top[x]]>dep[top[y]])x=fa[top[x]];else y=fa[top[y]]; return dep[x]<dep[y]?x:y; } void init(){ dep[rt]=1,top[rt]=rt; dfs(rt),dfs2(rt); for(int i=1;i<18;++i) for(int j=1;j<=rt;++j)F[i][j]=F[i-1][F[i-1][j]]; } int B[N]; inline void add(int i,int x){for(;i<N;i+=i&-i)B[i]+=x;} inline int ask(int i){int x=0;for(;i;i&=i-1)x+=B[i];return x;} struct colors{ set<int>s; void ADD(int x){ add(x,1); if(s.empty()){ s.insert(x); return; } auto nxt=s.lower_bound(x); if(nxt==s.begin()){ s.insert(x); add(dfn[LCA(idfn[x],idfn[*nxt])],-1); return; } auto pre=nxt;--pre; if(nxt==s.end()){ s.insert(x); add(dfn[LCA(idfn[x],idfn[*pre])],-1); return; } int lft=LCA(idfn[x],idfn[*pre]),rgt=LCA(idfn[x],idfn[*nxt]); int X=dep[lft]>dep[rgt]?lft:rgt; s.insert(x); add(dfn[X],-1); } void DEL(int x){ s.erase(x); add(x,-1); if(s.empty())return; auto nxt=s.lower_bound(x); if(nxt==s.begin()){ add(dfn[LCA(idfn[x],idfn[*nxt])],1); return; } auto pre=nxt;--pre; if(nxt==s.end()){ add(dfn[LCA(idfn[x],idfn[*pre])],1); return; } int lft=LCA(idfn[x],idfn[*pre]),rgt=LCA(idfn[x],idfn[*nxt]); int X=dep[lft]>dep[rgt]?lft:rgt; add(dfn[X],1); } }c[N]; void work(){ for(int i=1;i<=n;++i) c[col[i]].ADD(dfn[i]); for(int i=1;i<=Q;++i){ switch(q[i].op){ case 1:{ if(col[q[i].x]==q[i].y)break; c[col[q[i].x]].DEL(dfn[q[i].x]); c[col[q[i].x]=q[i].y].ADD(dfn[q[i].x]); break; } case 2:{ int p=LCA(q[i].x,q[i].y); printf("%d\n",dw[p]); break; } case 3:{ int x=q[i].x,y=q[i].y; for(int i=17;~i;--i) if(F[i][x]&&dw[F[i][x]]<=y)x=F[i][x]; printf("%d\n",ask(dfn[x]+sz[x]-1)-ask(dfn[x]-1)); break; } } } } } struct EDGE{ int u,v,w; inline int operator<(const EDGE&r)const{return w<r.w;} }e[N]; void kruskal(){ int tot=n; for(int i=1;i<=m;++i){ int u=find(e[i].u),v=find(e[i].v); if(u!=v){ ++tot; nt::addedge(tot,u,e[i].w),nt::addedge(tot,v,e[i].w); ff[u]=ff[v]=tot; } } nt::rt=tot; } int main(){ n=readint(),m=readint(),Q=readint(); for(int i=1;i<=n;++i)vec.push_back(col[i]=readint()); for(int i=1;i<=m;++i)e[i].u=readint(),e[i].v=readint(),e[i].w=readint(); sort(e+1,e+m+1); for(int i=1;i<=2*n;++i)ff[i]=i; for(int i=1;i<=Q;++i){ q[i].op=readint(),q[i].x=readint(),q[i].y=readint(); if(q[i].op==1)vec.push_back(q[i].y); } sort(vec.begin(),vec.end()),vec.erase(unique(vec.begin(),vec.end()),vec.end()); for(int i=1;i<=n;++i)col[i]=lower_bound(vec.begin(),vec.end(),col[i])-vec.begin(); for(int i=1;i<=Q;++i)if(q[i].op==1)q[i].y=lower_bound(vec.begin(),vec.end(),q[i].y)-vec.begin(); kruskal(); nt::init(); nt::work(); return 0; } ```