树链剖分【p2568】[SDOI2011]染色
Description
给定一颗有\(n\)个节点的无根树和\(m\)个操作,操作有\(2\)类:
- 1.将节点\(a\)到节点\(b\)路径上所有点染成颜色\(c\)
- 2.询问节点\(a\)到节点\(b\)路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由三段组成:"11","222"和“1”
请你写一个程序依次完成这\(m\)个操作.
Input
第一行包含两个整数\(n\)和\(m\),分别表示节点数和操作数.
第二行包含\(n\)个正整数表示\(n\)个节点的初始颜色.
下面\(n-1\)行每行包含两个整数\(x\)和\(y\),表示\(x\)和\(y\)之间有一条无向边.
下面\(m\)行每行描述一个操作:
"C a b c",表示这是一个染色操作,把节点\(a\)到节点\(b\)路径上所有点(包括\(a\)和\(b\))都染成颜色\(c\)
“Q a b”表示这是一个询问操作,询问节点\(a\)到节点\(b\)(包括\(a\)和\(b\))路径上的颜色段数量.
Output
对于每个询问操作,输出一行答案。
很明显,这是一个树剖题.
但是维护起来会很麻烦.qwq
首先明确我们的线段树需要维护什么东西.
- 我们需要维护颜色段的个数(题目要求啊,(#`O′))
由于线段树是每次将区间分成一半,所以我们需要考虑拼接。
因此我们需要维护的东西还有
- 当前节点的左子区间中的颜色段
- 当前节点的右子区间中的颜色段.
如果当前节点的左子区间的右子颜色段与当前节点的右子区间的左子颜色段相同,我们就需要拼接.(可能会有些难理解,请细细品读)
然后难点就在于剖分成链之后,我们跳转的时候,链顶与新的一部分的拼接.
这里以链的下端为\(L\),链的上端为\(R\),简单解释一下.
其中红色部分为已知部分的链,黑色部分为当前所求.
很容易发现,如果要拼接,我们需要将黑色部分左右端点调换,直接\(swap\)即可.

最后需要考虑的是当两端点在一条链上如何拼接,这里不再讨论,
请大家独立思考QwQ
本来应该一边切的,结果因为局部变量和重载出锅QAQ
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cctype>
#define ls o<<1
#define rs o<<1|1
#define R register
#define N 300008
using namespace std;
inline void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    x*=f;
}
struct cod{int lc,rc,sum;}tr[N<<2];
cod operator +( cod a, cod b)
{
	cod res;
	res.lc=a.lc;res.rc=b.rc;
	res.sum=a.sum+b.sum;
	if(a.rc==b.lc)res.sum--;
	return res;
}
int n,m,head[N],tot,a[N],tg[N<<2];
struct code{int u,v;}edge[N<<2];
inline void add(int x,int y)
{
    edge[++tot].u=head[x];
    edge[tot].v=y;
    head[x]=tot;
}
int size[N],son[N],f[N],depth[N];
void dfs1(int u,int fa)
{
    depth[u]=depth[fa]+1;f[u]=fa;size[u]=1;
    for(R int i=head[u];i;i=edge[i].u)
    {
        if(edge[i].v==fa)continue;
        dfs1(edge[i].v,u);
        size[u]+=size[edge[i].v];
        if(son[u]==-1 or size[son[u]]<size[edge[i].v])
            son[u]=edge[i].v;
    }
}
int dfn[N],fdfn[N],idx,top[N];
void dfs2(int u,int t)
{
    dfn[u]=++idx;fdfn[idx]=u;top[u]=t;
    if(son[u]==-1)return;
    dfs2(son[u],t);
    for(R int i=head[u];i;i=edge[i].u)
    {
        if(dfn[edge[i].v])continue;
        dfs2(edge[i].v,edge[i].v);
    }
}
void build(int o,int l,int r)
{
    if(l==r)
    {
        tr[o].lc=tr[o].rc=a[fdfn[l]];
        tr[o].sum=1;
        return;
    }
    int mid=(l+r)>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    tr[o]=tr[ls]+tr[rs];
}
inline void down(int o,int l,int r)
{
    if(tg[o])
    {
        tg[ls]=tr[ls].lc=tr[ls].rc=tg[o];
        tg[rs]=tr[rs].lc=tr[rs].rc=tg[o];
        tr[ls].sum=tr[rs].sum=1;
        tg[o]=0;
    }
}
void change(int o,int l,int r,int x,int y,int z)
{
    if(x<=l and y>=r)
    {
        tr[o].lc=tr[o].rc=tg[o]=z;
        tr[o].sum=1;
        return;
    }
    down(o,l,r);
    int mid=(l+r)>>1;
    if(x<=mid)change(ls,l,mid,x,y,z);
    if(y>mid)change(rs,mid+1,r,x,y,z);
    tr[o]=tr[ls]+tr[rs];
}
cod query(int o,int l,int r,int x,int y)
{
    if(x<=l and y>=r)return tr[o];
    down(o,l,r);
    int mid=(l+r)>>1;
    if(y<=mid)return query(ls,l,mid,x,y);
    if(x>mid)return query(rs,mid+1,r,x,y);
    return query(ls,l,mid,x,y)+query(rs,mid+1,r,x,y);
}
inline void tchange(int x,int y,int z)
{
    int fx=top[x],fy=top[y];
    while(fx!=fy)
    {
        if(depth[fx]>=depth[fy])
        {
            change(1,1,n,dfn[fx],dfn[x],z);
            x=f[fx];
        }
        else
        {
            change(1,1,n,dfn[fy],dfn[y],z);
            y=f[fy];
        }
        fx=top[x],fy=top[y];
    }
    if(dfn[x]>dfn[y])swap(x,y);
    change(1,1,n,dfn[x],dfn[y],z);
}
inline cod tquery(int x,int y)
{
    cod a,b,res;
    a.lc=a.rc=b.lc=b.rc=a.sum=b.sum=0;
    int fx=top[x],fy=top[y];
    while(fx!=fy)
    {
        if(depth[fx]>=depth[fy])
        {
            res=query(1,1,n,dfn[fx],dfn[x]);
            swap(res.lc,res.rc);
            a=a+res;
            x=f[fx];
        }
        else
        {
            res=query(1,1,n,dfn[fy],dfn[y]);
            swap(res.lc,res.rc);
            b=b+res;
            y=f[fy];
        }
        fx=top[x],fy=top[y];
    }
    if(dfn[x]>dfn[y])
    {
        swap(x,y);
        swap(a,b);
    }
    res=query(1,1,n,dfn[x],dfn[y]);
    a=a+res;
    swap(b.lc,b.rc);
    return a+b;
}
char s[8];
int main()
{
    in(n),in(m);memset(son,-1,sizeof son);
    for(R int i=1;i<=n;i++)in(a[i]);
    for(R int i=1,x,y;i<n;i++)
    {
        in(x),in(y);
        add(x,y),add(y,x);
    }
    dfs1(1,0);dfs2(1,1);build(1,1,n);
    for(R int a,b,c;m;m--)
    {
        scanf("%s",s+1);
        if(s[1]=='Q')
        {
            in(a),in(b);
            printf("%d\n",tquery(a,b).sum);
        }
        else
        {
            in(a),in(b),in(c);
            tchange(a,b,c);
        }
    }
}
树链剖分【p2568】[SDOI2011]染色的更多相关文章
- BZOJ 2243: [SDOI2011]染色 [树链剖分]
		2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6651 Solved: 2432[Submit][Status ... 
- bzoj-2243 2243: [SDOI2011]染色(树链剖分)
		题目链接: 2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6267 Solved: 2291 Descript ... 
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
		[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ... 
- bzoj 2243 [SDOI2011]染色(树链剖分,线段树)
		2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4637 Solved: 1726[Submit][Status ... 
- Bzoj 2243: [SDOI2011]染色  树链剖分,LCT,动态树
		2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 5020 Solved: 1872[Submit][Status ... 
- bzoj 2243 [SDOI2011]染色(树链剖分+线段树合并)
		[bzoj2243][SDOI2011]染色 2017年10月20日 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询 ... 
- bzoj2243[SDOI2011]染色 树链剖分+线段树
		2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 9012 Solved: 3375[Submit][Status ... 
- B20J_2243_[SDOI2011]染色_树链剖分+线段树
		B20J_2243_[SDOI2011]染色_树链剖分+线段树 一下午净调这题了,争取晚上多做几道. 题意: 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成 ... 
- bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分
		2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 7925 Solved: 2975[Submit][Status ... 
- bzoj 2243: [SDOI2011]染色 (树链剖分+线段树 区间合并)
		2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 9854 Solved: 3725[Submit][Status ... 
随机推荐
- hihocoder 1320 压缩字符串(字符串+dp)
			题解: 其实就是对应三种dp的转移方式 1.拼接类型 dp[i][j] = dp[i][c] + dp[c][j] 2.不变类型 dp[i][j] = j-i+1 3.重复类型(必须满足有k个循环节) ... 
- perl的Sys::Syslog模块(openlog,syslog,closelog函数,setlogsock)-自定义日志
			perl的Sys::Syslog模块(openlog,syslog,closelog函数,setlogsock)-自定义日志 http://blog.chinaunix.net/xmlrpc.php? ... 
- Word2010 自动生成二级编号
			http://jingyan.baidu.com/article/3ea5148901919752e61bbafe.html 
- C&C++——C函数与C++函数相互调用问题
			C C++相互调用 在项目中融合C和C++有时是不可避免的,在调用对方的功能函数的时候,或许会出现这样那样的问题,但只要我的C代码和我的C++代码分别都能成功编译,那其他就不是问题.近来在主程序是C语 ... 
- MySQL使用笔记(一)安装配置
			By francis_hao Nov 27,2016 一般软件的安装都是可以通过源码和安装包安装,源码安装可配置性好些,安装包安装比较省事,况且使用yum也可以解决依赖的问题,基本实现了一键 ... 
- Codeforces Round #525 (Div. 2)E. Ehab and a component choosing problem
			E. Ehab and a component choosing problem 题目链接:https://codeforces.com/contest/1088/problem/E 题意: 给出一个 ... 
- 图论:Stoer-Wagner算法
			利用Stoer-Wagner算法求无向图最小割 直接给出算法描述和过程实现: 算法步骤: . 设最小割cut=INF, 任选一个点s到集合A中, 定义W(A, p)为A中的所有点到A外一点p的权总和. ... 
- python中orm框架学习
			安装sqlalchemy pip3 install sqlalchemy 创建表结构: from sqlalchemy import Column,String,create_engine from ... 
- 【BZOJ3700】发展城市 [LCA][RMQ]
			发展城市 Time Limit: 20 Sec Memory Limit: 512 MB[Submit][Status][Discuss] Description 众所周知,Hzwer学长是一名高富 ... 
- Bzoj1917 [Ctsc2010]星际旅行
			Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 185 Solved: 118 Description 公元3000年,地球联盟已经攻占了银河系内的N ... 
