题意:树上每个结点有自己的颜色,支持两种操作:1.将u到v路径上的点颜色修改为c; 2.求u到v路径上有多少段不同的颜色。
分析:树剖之后用线段树维护区间颜色段数。区间查询区间修改。线段树结点中维护的有:段数,左端点颜色,右端点颜色和懒惰标记。
当区间合并时,若左孩子的右端点颜色和右孩子的左端点颜色相同,那么段数要减1。
区间修改时注意维护左右端点的颜色。
查询时若左右子区间连接处的颜色相同,段数减1。
在两点向一条链上寻找LCA时,每次查询都要保存该条链顶端的颜色,若该链顶端的颜色与下次查询的右端点相同,那么段数减1。
最后当两点回溯到一条链上之后,若两点对应各自上次回溯链顶端的颜色是否与查询区间的左右端点相同,则答案都需减1。
#include#include #include #include #define lson rt<<1#define rson rt<<1|1#define Lson l,m,lson#define Rson m+1,r,rsontypedef long long LL;using namespace std;const int maxn =1e5+5;struct Edge{ int to,next;}E[2*maxn];int n,head[maxn],tot;int cnt,idx,size[maxn],fa[maxn],son[maxn],dep[maxn],top[maxn],id[maxn],rnk[maxn];int a[maxn];void init(){ cnt=idx=tot=0; memset(head,-1,sizeof(head)); dep[1]=0,fa[1]=1,size[0]=0; memset(son,0,sizeof(son));}void AddEdge(int u,int v){ E[tot] = (Edge){v,head[u]}; head[u]=tot++;}void dfs1(int u){ size[u]=1; for(int i=head[u];~i;i=E[i].next){ int v=E[i].to; if(v!=fa[u]){ fa[v]=u; dep[v]=dep[u]+1; dfs1(v); size[u]+=size[v]; if(size[son[u]] >1; build(Lson); build(Rson); pushup(rt);}void update(int L,int R,int col,int l=1,int r=n,int rt=1){ if(L<=l && R>=r){ tree[rt].sum = tree[rt].add =1; tree[rt].lc = tree[rt].rc = col; return ; } pushdown(l,r,rt); int m =(l+r)>>1; if(L<=m) update(L,R,col,Lson); if(R>m) update(L,R,col,Rson); pushup(rt);}int query(int L,int R,int l=1,int r=n,int rt=1){ //单点 if(L==l) Lc = tree[rt].lc; if(R==r) Rc = tree[rt].rc; if(L<=l && R>=r) return tree[rt].sum; pushdown(l,r,rt); int m = (l+r)>>1 , ans=0; bool left = false; if(L<=m) { ans+=query(L,R,Lson); left = true; } if(R>m){ ans +=query(L,R,Rson); if(left && tree[lson].rc ==tree[rson].lc) ans--; } pushup(rt); return ans;}void CHANGE(int u,int v,int col){ while(top[u]!=top[v]){ if(dep[top[u]] dep[v]) swap(u,v); update(id[u],id[v],col);}int Qsum(int u,int v){ int c1=-1,c2=-1, ans=0; //记录上条链最左侧的颜色 while(top[u]!=top[v]){ if(dep[top[u]] dep[v]){swap(u,v);swap(c1,c2);} ans += query(id[u],id[v]); if(Lc==c1) ans--; if(Rc==c2) ans--; return ans; }int main(){ #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif int m,q,u,v; char op[5]; while(scanf("%d%d",&n,&m)==2){ init(); for(int i=1;i<=n;++i) scanf("%d",&a[i]); for(int i=1;i