正解:线段树+树链剖分
解题报告:
其实是道蛮板子的题,,,但因为我写得很呆然后写了贼久之后发现想法有问题要重构,就很难受,就先写个题解算了$kk$
考虑先跑个树剖,然后按$dfn$序建线段树,区间修改区间查询就行
然后唯一要注意细节的点就因为它是查询颜色段,所以当左侧的最靠右的颜色和右侧的最靠左的颜色相同的时候要答案减一.然后在树上跳的时候也是注意这个点.
然后因为我很呆,实现在树上跳的时候就用的两个结构体分别存了两侧的数量和边界颜色.
然后我发现到最后一步两个合并的时候我分不出左右就$GG$了,,,$QAQ$
然后我又很作,如果改成直接查询数量和左右节点就简单很多了,,,但我就是不想重构然后就疯狂拍疯狂$WA$疯狂调.
调了一年总算调完了$kk$
其实理顺思路的话还是没那么难的$kk$
$over$,反正就多理下思路注意到底怎么合并就完事$kk$.
#include<bits/stdc++.h> using namespace std; #define il inline #define gc getchar() #define t(i) edge[i].to #define ri register int #define rc register char #define rb register bool #define rp(i,x,y) for(ri i=x;i<=y;++i) #define my(i,x,y) for(ri i=x;i>=y;--i) #define e(i,x) for(ri i=head[x];i;i=edge[i].nxt) const int N=1e5+10; int n,m,col[N],ed_cnt,head[N],dfn[N],dfn_cnt,rk[N],top[N],sz[N],sn[N],dep[N],fa[N],qwq; struct ed{int to,nxt;}edge[N<<1]; struct node{int num,l,r,tag;node(ri x=0,ri y=0,ri z=0,ri p=0){num=x,l=y,r=z,tag=p;}void print(){printf("(%d,%d,%d)",num,l,r);}}tr[N<<2]; il int read() { rc ch=gc;ri x=0;rb y=1; while(ch!='-' && (ch>'9' || ch<'0'))ch=gc; if(ch=='-')ch=gc,y=0; while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc; return y?x:-x; } il bool rd(){rc ch=gc;while(ch!='C' && ch!='Q')ch=gc;return ch=='C';} void ad(ri x,ri y){edge[++ed_cnt]=(ed){x,head[y]};head[y]=ed_cnt;} void dfs(ri x) {sz[x]=1;e(i,x)if(!dep[t(i)]){dep[t(i)]=dep[x]+1;dfs(t(i));sz[x]+=sz[t(i)];if(sz[t(i)]>sz[sn[x]])sn[x]=t(i);}} void dfs2(ri x,ri tp) { top[x]=tp;rk[dfn[x]=++dfn_cnt]=x;if(sn[x])dfs2(sn[x],tp),fa[sn[x]]=x; e(i,x)if(!top[t(i)])dfs2(t(i),t(i)),fa[t(i)]=x; } il node merge(node gd,node gs) { gd.tag=gs.tag=0;if(!gd.num)return gs;if(!gs.num)return gd; gd.num+=gs.num;if(gd.r==gs.l)--gd.num;gd.r=gs.r;return gd; } il void pushdown(ri nw,ri l,ri r) { if(!tr[nw].tag)return; tr[nw<<1]=tr[nw<<1|1]=(node){1,tr[nw].tag,tr[nw].tag,tr[nw].tag};tr[nw].tag=0; } void build(ri nw,ri l,ri r) { if(l==r)return void(tr[nw]=(node){1,col[rk[l]],col[rk[l]]}); ri mid=(l+r)>>1;build(nw<<1,l,mid);build(nw<<1|1,mid+1,r);tr[nw]=merge(tr[nw<<1],tr[nw<<1|1]); } void modify(ri nw,ri l,ri r,ri to_l,ri to_r,ri dat) { if(to_l<=l && r<=to_r){return void(tr[nw]=(node){1,dat,dat,dat});} ri mid=(l+r)>>1;pushdown(nw,l,r); if(to_l<=mid)modify(nw<<1,l,mid,to_l,to_r,dat); if(to_r>mid)modify(nw<<1|1,mid+1,r,to_l,to_r,dat); tr[nw]=merge(tr[nw<<1],tr[nw<<1|1]); } node query(ri nw,ri l,ri r,ri to_l,ri to_r) { if(to_l<=l && r<=to_r)return tr[nw]; ri mid=(l+r)>>1;node ret;pushdown(nw,l,r); if(to_l<=mid)ret=merge(ret,query(nw<<1,l,mid,to_l,to_r)); if(to_r>mid)ret=merge(ret,query(nw<<1|1,mid+1,r,to_l,to_r)); return ret; } int main() { freopen("2486.in","r",stdin);freopen("2486.out","w",stdout); n=read();m=read();rp(i,1,n)col[i]=read();rp(i,1,n-1){ri x=read(),y=read();ad(x,y);ad(y,x);} dep[1]=1;dfs(1);dfs2(1,1);build(1,1,n); while(m--) { rb op=rd(); if(op) { ri x=read(),y=read(),z=read(); while(top[x]!=top[y]) {if(dep[top[x]]<dep[top[y]])swap(x,y);modify(1,1,n,dfn[top[x]],dfn[x],z);x=fa[top[x]];} if(dep[x]<dep[y])swap(x,y);modify(1,1,n,dfn[y],dfn[x],z);continue; } ri x=read(),y=read();node asx,asy; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) {node tmp=query(1,1,n,dfn[top[y]],dfn[y]);asy.num+=tmp.num-(tmp.r==asy.r);asy.r=tmp.l;y=fa[top[y]];} else {node tmp=query(1,1,n,dfn[top[x]],dfn[x]);asx.num+=tmp.num-(tmp.r==asx.r);asx.r=tmp.l;x=fa[top[x]];} } if(dep[x]<dep[y]){node tmp=query(1,1,n,dfn[x],dfn[y]);asy.num+=tmp.num-(tmp.r==asy.r);asy.r=tmp.l;} else{node tmp=query(1,1,n,dfn[y],dfn[x]);asx.num+=tmp.num-(tmp.r==asx.r);asx.r=tmp.l;} printf("%d ",asx.num+asy.num-(asx.r==asy.r)); } return 0; }