Description

给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),
如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。

Input

第一行包含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)路径上的颜色段数量。

Output

对于每个询问操作,输出一行答案。

Sample Input

6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5

Sample Output

3
1
2

解题思路:

1.树链剖分:

只修改链,不修改关系,树链剖分。

线段树维护树链剖分序。

时间复杂度O(nlogn2)

代码:

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define lll spc<<1
#define rrr spc<<1|1
using std::min;
using std::max;
using std::swap;
struct trnt{
int lc;
int rc;
int lzt;
int val;
}tr[];
struct pnt{
int hd;
int col;
int mxs;
int ind;
int fa;
int tp;
int wgt;
int dp;
}p[];
struct ent{
int twd;
int lst;
}e[];
struct bag{
int cl;
int cr;
int vl;
bag friend operator + (bag a,bag b)
{
if(!a.cl)
a.cl=b.cl;
if(!b.cr)
b.cr=a.cr;
return (bag){a.cl,b.cr,(a.vl+b.vl-(a.cr==b.cl)<)?:(a.vl+b.vl-(a.cr==b.cl))};
}
};
int n,m;
int cnt;
int dfn;
char cmd[];
void ade(int f,int t)
{
cnt++;
e[cnt].twd=t;
e[cnt].lst=p[f].hd;
p[f].hd=cnt;
return ;
}
void pushup(int spc)
{
tr[spc].lc=tr[lll].lc;
tr[spc].rc=tr[rrr].rc;
tr[spc].val=tr[lll].val+tr[rrr].val-(tr[lll].rc==tr[rrr].lc);
return ;
}
void chg(int spc,int v)
{
tr[spc].val=;
tr[spc].lc=tr[spc].rc=v;
tr[spc].lzt=v;
return ;
}
void pushdown(int spc)
{
if(tr[spc].lzt)
{
chg(lll,tr[spc].lzt);
chg(rrr,tr[spc].lzt);
tr[spc].lzt=;
}
return ;
}
void build(int l,int r,int pos,int spc,int v)
{
if(l==r)
{
tr[spc].lc=tr[spc].rc=v;
tr[spc].val=;
tr[spc].lzt=;
return ;
}
int mid=(l+r)>>;
if(pos<=mid)
build(l,mid,pos,lll,v);
else
build(mid+,r,pos,rrr,v);
pushup(spc);
return ;
}
void Basic_dfs(int x,int f)
{
p[x].dp=p[f].dp+;
p[x].fa=f;
int maxs=-;
p[x].wgt=;
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(to==f)
continue;
Basic_dfs(to,x);
p[x].wgt+=p[to].wgt;
if(p[to].wgt>maxs)
{
maxs=p[to].wgt;
p[x].mxs=to;
}
}
return ;
}
void Build_dfs(int x,int tpl)
{
if(!x)
return ;
p[x].tp=tpl;
p[x].ind=++dfn;
build(,n,dfn,,p[x].col);
Build_dfs(p[x].mxs,tpl);
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(p[to].ind)
continue;
Build_dfs(to,to);
}
}
void update(int l,int r,int ll,int rr,int spc,int v)
{
if(ll>rr)
return ;
if(l>rr||ll>r)
return ;
pushdown(spc);
if(ll<=l&&r<=rr)
{
chg(spc,v);
return ;
}
int mid=(l+r)>>;
update(l,mid,ll,rr,lll,v);
update(mid+,r,ll,rr,rrr,v);
pushup(spc);
return ;
}
bag mk(int a,int b,int c)
{
return (bag){a,b,c};
}
bag ask(int l,int r,int ll,int rr,int spc)
{
if(l>rr||ll>r)
return mk(,,);
pushdown(spc);
if(ll<=l&&r<=rr)
return mk(tr[spc].lc,tr[spc].rc,tr[spc].val);
int mid=(l+r)>>;
return ask(l,mid,ll,rr,lll)+ask(mid+,r,ll,rr,rrr);
}
int lca(int x,int y)
{
while(p[x].tp!=p[y].tp)
{
if(p[p[x].tp].dp<p[p[y].tp].dp)
swap(x,y);
x=p[p[x].tp].fa;
}
if(p[x].dp>p[y].dp)
swap(x,y);
return x;
}
void rvs(bag &a)
{
swap(a.cl,a.cr);
return ;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
scanf("%d",&p[i].col);
for(int i=;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
ade(a,b);
ade(b,a);
}
Basic_dfs(,);
Build_dfs(,);
while(m--)
{
scanf("%s",cmd);
if(cmd[]=='C')
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
int f=lca(a,b);
while(p[a].tp!=p[f].tp)
{
update(,dfn,p[p[a].tp].ind,p[a].ind,,c);
a=p[p[a].tp].fa;
}
update(,dfn,p[f].ind,p[a].ind,,c);
a=b;
while(p[a].tp!=p[f].tp)
{
update(,dfn,p[p[a].tp].ind,p[a].ind,,c);
a=p[p[a].tp].fa;
}
update(,dfn,p[f].ind,p[a].ind,,c);
}
if(cmd[]=='Q')
{
int a,b; scanf("%d%d",&a,&b);
int f=lca(a,b);
bag ans=(bag){,,};
while(p[a].tp!=p[f].tp)
{
ans=ask(,dfn,p[p[a].tp].ind,p[a].ind,)+ans;
a=p[p[a].tp].fa;
}
if(a!=f)
ans=ask(,dfn,p[f].ind+,p[a].ind,)+ans;
bag ams=(bag){,,};
a=b;
while(p[a].tp!=p[f].tp)
{
ams=ask(,dfn,p[p[a].tp].ind,p[a].ind,)+ams;
a=p[p[a].tp].fa;
}
if(a!=f)
ams=ask(,dfn,p[f].ind+,p[a].ind,)+ams;
ans=ask(,dfn,p[f].ind,p[f].ind,)+ans;
rvs(ans);
ans=ans+ams;
printf("%d\n",ans.vl);
}
}
return ;
}

2.LCT:

比较板子了。

每次维护左侧颜色和右侧颜色(注意特判0节点值)

反转时要反转左右颜色。

路径提取一下输出答案就好了。

时间复杂度O(nlogn)理论上比树剖快

但是:

蒟蒻的我:splay常数居然比logn大

代码:

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define lll tr[spc].ch[0]
#define rrr tr[spc].ch[1]
#define ls ch[0]
#define rs ch[1]
using std::swap;
struct trnt{
int ch[];
int fa;
int lzt;
int chg;
int sum;
int val;
int lc;
int rc;
int wgt;
bool anc;
}tr[];
int n,m;
char cmd[];
bool whc(int spc)
{
return tr[tr[spc].fa].rs==spc;
}
void pushup(int spc)
{
tr[spc].wgt=tr[lll].wgt+tr[rrr].wgt+;
tr[spc].sum=tr[lll].sum+tr[rrr].sum+-(tr[lll].rc==tr[spc].val)-(tr[rrr].lc==tr[spc].val);
tr[spc].lc=tr[lll].lc?tr[lll].lc:tr[spc].val;
tr[spc].rc=tr[rrr].rc?tr[rrr].rc:tr[spc].val;
return ;
}
void trr(int spc)
{
if(!spc)
return ;
swap(lll,rrr);
swap(tr[spc].lc,tr[spc].rc);
tr[spc].lzt^=;
return ;
}
void upd(int spc,int v)
{
if(!spc)
return ;
tr[spc].val=tr[spc].lc=tr[spc].rc=v;
tr[spc].sum=;
tr[spc].chg=v;
return ;
}
void pushdown(int spc)
{
if(tr[spc].lzt)
{
trr(lll);
trr(rrr);
tr[spc].lzt=;
}
if(tr[spc].chg)
{
upd(lll,tr[spc].chg);
upd(rrr,tr[spc].chg);
tr[spc].chg=;
}
return ;
}
void recal(int spc)
{
if(!tr[spc].anc)
recal(tr[spc].fa);
pushdown(spc);
return ;
}
void rotate(int spc)
{
int f=tr[spc].fa;
bool k=whc(spc);
tr[f].ch[k]=tr[spc].ch[!k];
tr[spc].ch[!k]=f;
if(tr[f].anc)
{
tr[spc].anc=;
tr[f].anc=;
}else
tr[tr[f].fa].ch[whc(f)]=spc;
tr[spc].fa=tr[f].fa;
tr[f].fa=spc;
tr[tr[f].ch[k]].fa=f;
pushup(f);
pushup(spc);
return ;
}
void splay(int spc)
{
recal(spc);
while(!tr[spc].anc)
{
int f=tr[spc].fa;
if(tr[f].anc)
{
rotate(spc);
return ;
}
if(whc(spc)^whc(f))
rotate(spc);
else
rotate(f);
rotate(spc);
}
return ;
}
void access(int spc)
{
int lst=;
while(spc)
{
splay(spc);
tr[rrr].anc=;
tr[lst].anc=;
rrr=lst;
pushup(spc);
lst=spc;
spc=tr[spc].fa;
}
return ;
}
void Mtr(int spc)
{
access(spc);
splay(spc);
trr(spc);
return ;
}
void split(int x,int y)
{
Mtr(x);
access(y);
splay(y);
return ;
}
void link(int x,int y)
{
Mtr(x);
tr[x].fa=y;
return;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
tr[i].anc=;
scanf("%d",&tr[i].val);
tr[i].lc=tr[i].rc=tr[i].val;
}
for(int i=;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
link(a,b);
}
while(m--)
{
scanf("%s",cmd);
if(cmd[]=='Q')
{
int a,b;
scanf("%d%d",&a,&b);
split(a,b);
printf("%d\n",tr[b].sum);
}else{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
split(a,b);
upd(b,c);
}
}
return ;
}

BZOJ2243: [SDOI2011]染色(树链剖分/LCT)的更多相关文章

  1. Bzoj 2243: [SDOI2011]染色 树链剖分,LCT,动态树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 5020  Solved: 1872[Submit][Status ...

  2. bzoj2243[SDOI2011]染色 树链剖分+线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 9012  Solved: 3375[Submit][Status ...

  3. BZOJ2243[SDOI2011]染色——树链剖分+线段树

    题目描述 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段), 如“112221 ...

  4. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  5. bzoj-2243 2243: [SDOI2011]染色(树链剖分)

    题目链接: 2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6267  Solved: 2291 Descript ...

  6. BZOJ2243 洛谷2486 [SDOI2011]染色 树链剖分

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ2243 题目传送门 - 洛谷2486 题意概括 一棵树,共n个节点. 让你支持以下两种操作,共m次操 ...

  7. BZOJ 2243: [SDOI2011]染色 [树链剖分]

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6651  Solved: 2432[Submit][Status ...

  8. BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...

  9. BZOJ 2243: [SDOI2011]染色 树链剖分+线段树区间合并

    2243: [SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数 ...

  10. 2243: [SDOI2011]染色(树链剖分+线段树)

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 8400  Solved: 3150[Submit][Status ...

随机推荐

  1. 124.C++输出小结

    #include <iostream> #include <iomanip> using namespace std; void main() { ////调用cout的成员函 ...

  2. 实时监控Cat之旅~分布式消息树的实现原理与测试

    大众点评的老吴在InfoQ上讲了Cat之后,有不少同仁开始关注这个实时监控系统,但学习的文章甚少,在GitHub上也是一言代过,给我们这些开发人员留下了N多个疑问,一时间不知道去哪里问,向谁去问了,通 ...

  3. Google Nexus 5x Android 7.0 Root

    很久没有写东西了,准备重新养成这个好习惯.因为自己一直在用Nexus,前段时间自己的Nexus5老的不行了,所以买了台5x,一直没时间root,今天有时间终于有时间弄一下. 在这里整理分享一下. 开始 ...

  4. openSUSE leap 42.3 添加HP Laserjet Pro M128fn打印机和驱动

    一.安装驱动 YaST控制中心->软件管理->搜索->hplip 安装hplip 如下图: HPLIP(Linux Imaging and Printing Object)以前有hp ...

  5. 好吧,左小波出山了——ie8兼容indexOf问题

    我,还是一个不懂世事的毛头小子,第一次写博.万事开头难,没事咱慢慢来.咳,练文笔吗.我觉得写东西最锻炼逻辑思维,我是一个不善于表达的人,可能是程序员的通病,但你看看人家王小波,八九十年代的作家兼职程序 ...

  6. 使用PyV8模块破解网站加密cookie

    PyV8是Chromium中内嵌的javascript引擎,号称跑的最快.PyV8是用Python在V8的外部API包装了一个python壳,这样便可以使python可以直接与javascript操作 ...

  7. 基于promise用于浏览器和node.js的http客户端的axios

    axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,它本身具有以下特征: 从浏览器中创建 XMLHttpRequest 从 node.js 发出 http 请求 支 ...

  8. 使用IntelliJ IDEA开发前的基本设置,有助于提高开发效率

    2.界面字体大小设置 File菜单->Settings->Appearance->Override default fonts by(not recommended): Name:宋 ...

  9. HDU 3714 Error Curves

    Error Curves 思路:这个题的思路和上一个题的思路一样,但是这个题目卡精度,要在计算时,卡到1e-9. #include<cstdio> #include<cstring& ...

  10. ArcGIS Engine中添加点、线、面元素

    转自原文 ArcGIS Engine中添加点.线.面元素 此种方式为IElement的方式在axMapControl的GraphicsContainer中好绘制图形. //画点 IPoint pt = ...