给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。
对于每个询问操作,输出一行答案。
数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。
第一轮day1
首先对树轻重链剖分,维护线段树一段的颜色,最左边和最右边的颜色即可。
#include "iostream" #include "stdio.h" using namespace std; inline void read(int &v){ char ch=getchar();v=0; while(ch>'9'||ch<'0')ch=getchar(); do{v=v*10+ch-'0',ch=getchar();} while(ch<='9'&&ch>='0'); } const int N=100005,oo=0x7fffffff,G=17; int n,m,color[N],push[N],size[N],deep[N]; int head[N],next[2*N],route[2*N],fa[N][G+1]; int pos[N],belong[N],tmp; inline void add_arc(int x,int y,int i){ next[i]=head[x]; route[i]=y; head[x]=i; }//O(1) inline int lca(int u,int v){ if(deep[u]<deep[v]) swap(u,v); int len=deep[u]-deep[v],i; for (i=G;i>=0;i--) if(len&(1<<i)) u=fa[u][i]; for (i=G;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i]; if(u==v) return u; return fa[u][0]; }//O(log n) int dfs1(int v){int k;size[v]=1; for (k=1;(1<<k)<=deep[v];k++){ fa[v][k]=fa[fa[v][k-1]][k-1]; } for (k=head[v];k;k=next[k]){ if(deep[route[k]]>deep[v]) {deep[route[k]]=deep[v]+1; fa[route[k]][0]=v;dfs1(route[k]); size[v]+=size[route[k]];} } return size[v]; }//O(n) void dfs2(int v,int bel){ int k,u=0; belong[v]=bel; pos[v]=++tmp; push[tmp]=color[v]; for (k=head[v];k;k=next[k]) if(size[u]<size[route[k]]&&deep[route[k]]>deep[v]) u=route[k]; if(!u)return; dfs2(u,bel); for (k=head[v];k;k=next[k]) if(route[k]!=u&&deep[route[k]]>deep[v]) dfs2(route[k],route[k]); }//O(n) void build(){int i,u,v; for (i=1;i<n;i++){ read(u),read(v); add_arc(u,v,2*i-1); add_arc(v,u,2*i); }deep[1]=0; dfs1(1),dfs2(1,1); }//O(n) struct SegMent{ int l,r,color; int lco,rco; int ans; } seg[N<<2]; inline void Build(int l,int r,int v){int mid=(l+r)>>1; seg[v].l=l,seg[v].r=r;seg[v].color=0; if(l==r){seg[v].color=seg[v].lco=seg[v].rco=push[l]+1; seg[v].ans=1; return ;}Build(l,mid,v<<1),Build(mid+1,r,v<<1|1); seg[v].lco=seg[v<<1].lco,seg[v].rco=seg[v<<1|1].rco; seg[v].ans=seg[v<<1].ans+seg[v<<1|1].ans-(seg[v<<1].rco==seg[v<<1|1].lco); }//O(n) inline void paint(int l,int r,int c,int v){ int mid=(seg[v].l+seg[v].r)>>1; if(seg[v].l==l&&seg[v].r==r) { seg[v].color=seg[v].lco=seg[v].rco=c; seg[v].ans=1; return ;} if(seg[v].color==c) return; if(seg[v].color) { seg[v<<1].color=seg[v<<1|1].color=seg[v<<1].lco= seg[v<<1].rco=seg[v<<1|1].lco=seg[v<<1|1].rco=seg[v].color; seg[v<<1].ans=seg[v<<1|1].ans=1; seg[v].color=0; } if(r<=mid) paint(l,r,c,v<<1); else if(l>mid) paint(l,r,c,v<<1|1); else paint(l,mid,c,v<<1),paint(mid+1,r,c,v<<1|1); seg[v].lco=seg[v<<1].lco,seg[v].rco=seg[v<<1|1].rco; seg[v].ans=seg[v<<1].ans+seg[v<<1|1].ans-(seg[v<<1].rco==seg[v<<1|1].lco); }//O(log n) inline int count(int v,int l,int r,int last,int &ans){ int mid=(seg[v].l+seg[v].r)>>1; if(seg[v].l==l&&seg[v].r==r) { ans+=seg[v].ans-(last==seg[v].rco); return seg[v].lco; } if(seg[v].color) { ans+=last!=seg[v].rco; return seg[v].color; } if(r<=mid) return count(v<<1,l,r,last,ans); else if(l>mid) return count(v<<1|1,l,r,last,ans); return count(v<<1,l,mid,count(v<<1|1,mid+1,r,last,ans),ans); }//O(log n) inline void Color(int u,int v,int co){ int t=lca(u,v);swap(v,t); while (belong[u]!=belong[v]){ paint(pos[belong[u]],pos[u],co,1); u=fa[belong[u]][0]; } paint(pos[v],pos[u],co,1);swap(u,t); while (belong[u]!=belong[v]){ paint(pos[belong[u]],pos[u],co,1); u=fa[belong[u]][0]; } paint(pos[v],pos[u],co,1); }//O(log n^2) inline int Query(int u,int v){ int t=lca(u,v);swap(v,t); int ans=0,last=-1; while (belong[u]!=belong[v]){ last=count(1,pos[belong[u]],pos[u],last,ans); u=fa[belong[u]][0]; } count(1,pos[v],pos[u],last,ans);swap(u,t);last=-1; while (belong[u]!=belong[v]){ last=count(1,pos[belong[u]],pos[u],last,ans); u=fa[belong[u]][0]; } last=count(1,pos[v],pos[u],last,ans); return ans-1; }//O(log n^2) void work(){ for (int i=0;i<m;i++){ char ch=getchar();int u,v,c; while(ch!='Q'&&ch!='C')ch=getchar(); read(u),read(v); if(ch=='C') read(c),Color(u,v,c+1); else printf("%d\n",Query(u,v)); } }//O(m log n^2 + n) int main(){ // freopen("paint.in","r",stdin); // freopen("paint.out","w",stdout); read(n),read(m); for(int i=1;i<=n;i++) read(color[i]),deep[i]=oo; build(),Build(1,n,1),work(); return 0; }//O(m log n^2 + n)
标复杂度是因为我一开始写TLE了……到最后才发现在LCA那出了一点小问题……