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. HDU3265 Examining the Rooms【stirling数】

    题目链接: http://acm.hdu.edu.cn/showproblem.php? pid=3625 题目大意: 有N个房间,每一个房间的要是随机放在某个房间内,概率同样.有K次炸门的机会. 求 ...

  2. Xamarin大佬的地址

    https://www.cnblogs.com/hlx-blogs/p/7266098.html http://www.cnblogs.com/GuZhenYin/p/6971069.html

  3. 配置CiscoWorks 2000 ANI同步

    配置CiscoWorks 2000 ANI同步       在CiscoWorks 2000的LAN ManagementSolution(LMS)中,Cisco包含了一种ANI的自动发现过程和Res ...

  4. shell脚本的if判断语句

    if条件判断语句 if (表达式) #if ( Variable in Array ) 语句1 else 语句2 fi 1.测试数字大小 #!/bin/sh NUM=100 if (( $NUM &g ...

  5. Scrapy中将数据保存至数据库

    一.在settings.py文件中配置数据库连接参数 # 数据库连接参数 DB_HOST = '192.168.183.1' DB_PORT = 3306 DB_USER = 'root' DB_PA ...

  6. 五十个UI设计资源网站

    五十个UI设计资源网站 用户体验团队网站 1.UCD大社区 http://ucdchina.com/ 2.腾讯WSD http://wsd.tencent.com/ 3.腾讯CDC http://cd ...

  7. js插件---tree(多级文件)插件如何使用

    js插件---tree(多级文件)插件如何使用 一.总结 一句话总结:还是一般的引入js和css后js调用的方式, 只不过tree调用的时候必须设置一个 HTML 模板(就是调用的那段html代码,别 ...

  8. Zabbix快速入门

    模板的管理与使用 一 模板 模板是zabbix的核心,因为模板继承了所有要监控的内容,以及所要展示的图形等等,zabbix的安装部署完成之后,自带了很多模板(网络设备模板,操作系统模板,常用应用软件模 ...

  9. 用Nagios监控Sql Server服务器

    在Suse 下配置Nagios来监控Ms SQL Server操作演示 本文出自 "李晨光原创技术博客" 博客,谢绝转载!

  10. deep-in-es6(二)

    es6-生成器Generators: eg: function* quips(name) { yield "您好"+name+"!"; if(name.star ...