正解:线段树+树链剖分

解题报告:

传送门$QwQ$

其实是道蛮板子的题,,,但因为我写得很呆然后写了贼久之后发现想法有问题要重构,就很难受,就先写个题解算了$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+;
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<<];
struct node{int num,l,r,tag;node(ri x=,ri y=,ri z=,ri p=){num=x,l=y,r=z,tag=p;}void print(){printf("(%d,%d,%d)",num,l,r);}}tr[N<<]; il int read()
{
rc ch=gc;ri x=;rb y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),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]=;e(i,x)if(!dep[t(i)]){dep[t(i)]=dep[x]+;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=;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<<]=tr[nw<<|]=(node){,tr[nw].tag,tr[nw].tag,tr[nw].tag};tr[nw].tag=;
}
void build(ri nw,ri l,ri r)
{
if(l==r)return void(tr[nw]=(node){,col[rk[l]],col[rk[l]]});
ri mid=(l+r)>>;build(nw<<,l,mid);build(nw<<|,mid+,r);tr[nw]=merge(tr[nw<<],tr[nw<<|]);
}
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){,dat,dat,dat});}
ri mid=(l+r)>>;pushdown(nw,l,r);
if(to_l<=mid)modify(nw<<,l,mid,to_l,to_r,dat);
if(to_r>mid)modify(nw<<|,mid+,r,to_l,to_r,dat);
tr[nw]=merge(tr[nw<<],tr[nw<<|]);
}
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)>>;node ret;pushdown(nw,l,r);
if(to_l<=mid)ret=merge(ret,query(nw<<,l,mid,to_l,to_r));
if(to_r>mid)ret=merge(ret,query(nw<<|,mid+,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,,n)col[i]=read();rp(i,,n-){ri x=read(),y=read();ad(x,y);ad(y,x);}
dep[]=;dfs();dfs2(,);build(,,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(,,n,dfn[top[x]],dfn[x],z);x=fa[top[x]];}
if(dep[x]<dep[y])swap(x,y);modify(,,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(,,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(,,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(,,n,dfn[x],dfn[y]);asy.num+=tmp.num-(tmp.r==asy.r);asy.r=tmp.l;}
else{node tmp=query(,,n,dfn[y],dfn[x]);asx.num+=tmp.num-(tmp.r==asx.r);asx.r=tmp.l;}
printf("%d\n",asx.num+asy.num-(asx.r==asy.r)); }
return ;
}

洛谷$P2486\ [SDOI2011]$染色 线段树+树链剖分的更多相关文章

  1. 洛谷P2486 [SDOI2011]染色 题解 树链剖分+线段树

    题目链接:https://www.luogu.org/problem/P2486 首先这是一道树链剖分+线段树的题. 线段树部分和 codedecision P1112 区间连续段 一模一样,所以我们 ...

  2. 洛谷 P2486 [SDOI2011]染色(树链剖分+线段树)

    题目链接 题解 比较裸的树链剖分 好像树链剖分的题都很裸 线段树中维护一个区间最左和最右的颜色,和答案 合并判断一下中间一段就可以了 比较考验代码能力 Code #include<bits/st ...

  3. 洛谷P2486 [SDOI2011]染色(树链剖分+线段树判断边界)

    [题目链接] [思路]: 涉及到树上区间修改操作,所以使用树链剖分,涉及到区间查询,所以使用线段树. update操作时,就正常操作,难点在于query操作的计数. 因为树链剖分的dfs序只能保证一条 ...

  4. 洛谷 P2486 [SDOI2011]染色 树链剖分

    目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例: 输出样例: 说明 思路 PushDown与Update Q AC代码 总结与拓展 题面 题目链接 P2486 ...

  5. 洛谷 P4292 - [WC2010]重建计划(长链剖分+线段树)

    题面传送门 我!竟!然!独!立!A!C!了!这!道!题!incredible! 首先看到这类最大化某个分式的题目,可以套路地想到分数规划,考虑二分答案 \(mid\) 并检验是否存在合法的 \(S\) ...

  6. 洛谷P2486 [SDOI2011]染色

    题目描述 输入输出格式 输入格式: 输出格式: 对于每个询问操作,输出一行答案. 输入输出样例 输入样例#1: 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C ...

  7. 线段树&数链剖分

    傻逼线段树,傻逼数剖 线段树 定义: 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 使用线段树可以快速的查找某一个节点在若干条线段中出现 ...

  8. P2486 [SDOI2011]染色 区间合并+树链剖分(加深对线段树的理解)

    #include<bits/stdc++.h> using namespace std; ; struct node{ int l,r,cnt,lazy; node(,,,):l(l1), ...

  9. P2486 [SDOI2011]染色 区间合并+树链剖分(加深对线段树的理解)

    #include<bits/stdc++.h> using namespace std; ; struct node{ int l,r,cnt,lazy; node(,,,):l(l1), ...

随机推荐

  1. 模板—LCT

    #include<iostream> #include<cstring> #include<cstdio> #define LL long long using n ...

  2. HZOJ Blue

    Blue: 贪心. 我们不妨给蛤定一个先后顺序,则贪心策略即从右至左每只蛤依次往最远的石子跳. 证明: 如果最右的蛤不往最远的石子跳,而是选择了一个较近的石子,那么必然会存在一个该蛤左边的蛤越过了它跳 ...

  3. zip解决杨辉三角问题

    杨辉三角原型: / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ 实现: a = [1] while True: print(a) ...

  4. mysql数据库之去重

    利用 distinct :对需要处理的字段进行去重 select  distinct 字段名 from 表名 去重以后 利用group by select * from 表名 group by 字段名 ...

  5. Python 进阶02 文本文件的输入输出

    Python 具有基本的文本文件读写功能,Python的标准库提供有更丰富的读写功能. 文本文件的读写主要通过open()所构建的文件对象来实现 创建文件对象 我们打开一个文件,并适用一个对象来表示该 ...

  6. saltStack 状态模块(状态间的关系)

    unless onlyif:状态间的条件判断,主要用于cmd状态模块 常用方法:    onlyif:检查的命令,仅当'onlyif'  选项指向的命令返回true时才执行name 定义的命 unle ...

  7. ORA错误查询手册

    ORA-00910: 指定した長さがデータ型に対して長すぎます 原因: データ型CHARまたはRAWに対して指定した長さは.2000を超える値または4000を超える値であるため無効です. 処置: 指定 ...

  8. SuperSocket通过 SessionID 获取 Session

    前面提到过,如果你获取了连接的 Session 实例,你就可以通过 "Send()" 方法向客户端发送数据.但是在某些情况下,你无法直接获取 Session 实例. SuperSo ...

  9. Python--day27--内置函数isinstance和issubclass方法

  10. JPA+Postgresql+Spring Data Page分页失败

    按照示例进行如下代码编写 Repository Page<DeviceEntity> findByTenantId(int tenantId, Pageable pageable); se ...