BZOJ 2243 [SDOI2011]染色:树剖【维护路径上颜色段】
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2243
题意:
给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如"112221"由3段组成:"11"、"222"和"1"。
请你写一个程序依次完成这m个操作。
题解:
树剖。
线段树上维护区间颜色段,每个节点:
dat[]:当前区间的颜色段数量
st[]:修改标记
lc[] and rc[]:当前区间的最左端和最右端颜色
lson[] and rson[]:左右儿子编号
线段树部分见NOI 2007 项链工厂。
树剖query中,每次a = par[tp[a]]往上跳之前,先判断getcol(dfsx[tp[a]]) == getcol(dfsx[par[tp[a]]])
如果相等,上下两端合并,sum--。
AC Code:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#define MAX_N 1000005 using namespace std; int n,m;
int tot=;
int cnt=;
int c[MAX_N];
int dat[MAX_N];
int st[MAX_N];
int lc[MAX_N];
int rc[MAX_N];
int lson[MAX_N];
int rson[MAX_N];
int par[MAX_N];
int dep[MAX_N];
int siz[MAX_N];
int tp[MAX_N];
int son[MAX_N];
int dfsx[MAX_N];
int idx[MAX_N];
vector<int> edge[MAX_N]; void read()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
scanf("%d",&c[i]);
}
int a,b;
for(int i=;i<n;i++)
{
scanf("%d%d",&a,&b);
edge[a].push_back(b);
edge[b].push_back(a);
}
} void push_down(int now)
{
if(st[now]!=-)
{
dat[lson[now]]=dat[rson[now]]=;
st[lson[now]]=st[rson[now]]=st[now];
lc[lson[now]]=rc[lson[now]]=lc[rson[now]]=rc[rson[now]]=st[now];
st[now]=-;
}
} void push_up(int now)
{
dat[now]=;
lc[now]=lc[lson[now]];
rc[now]=rc[rson[now]];
if(lson[now]) dat[now]+=dat[lson[now]];
if(rson[now]) dat[now]+=dat[rson[now]];
if(lson[now] && rson[now] && rc[lson[now]]==lc[rson[now]]) dat[now]--;
} int build(int l,int r)
{
int rt=++tot;
dat[rt]=;
st[rt]=-;
lc[rt]=c[idx[l]];
rc[rt]=c[idx[r]];
lson[rt]=rson[rt]=;
if(l<r)
{
int mid=(l+r)>>;
lson[rt]=build(l,mid);
rson[rt]=build(mid+,r);
push_up(rt);
}
return rt;
} void update(int a,int b,int k,int l,int r,int x)
{
if(a<=l && r<=b)
{
dat[k]=;
st[k]=lc[k]=rc[k]=x;
return;
}
if(r<a || b<l) return;
push_down(k);
int mid=(l+r)>>;
update(a,b,lson[k],l,mid,x);
update(a,b,rson[k],mid+,r,x);
push_up(k);
} int query(int a,int b,int k,int l,int r)
{
if(a<=l && r<=b) return dat[k];
if(r<a || b<l) return ;
push_down(k);
int mid=(l+r)>>;
int ans=;
if(a<=mid) ans+=query(a,b,lson[k],l,mid);
if(b>mid) ans+=query(a,b,rson[k],mid+,r);
if(a<=mid && b>mid && rc[lson[k]]==lc[rson[k]]) ans--;
return ans;
} int getcol(int p,int k,int l,int r)
{
if(l==r) return lc[k];
push_down(k);
int mid=(l+r)>>;
if(p<=mid) return getcol(p,lson[k],l,mid);
else return getcol(p,rson[k],mid+,r);
} void dfs1(int now,int p,int d)
{
par[now]=p;
dep[now]=d;
siz[now]=;
for(int i=;i<edge[now].size();i++)
{
int temp=edge[now][i];
if(temp!=p)
{
dfs1(temp,now,d+);
siz[now]+=siz[temp];
}
}
} void dfs2(int now,int anc)
{
tp[now]=anc;
son[now]=-;
cnt++;
idx[cnt]=now;
dfsx[now]=cnt;
for(int i=;i<edge[now].size();i++)
{
int temp=edge[now][i];
if((son[now]==- || siz[temp]>siz[son[now]]) && temp!=par[now])
{
son[now]=temp;
}
}
if(son[now]!=-) dfs2(son[now],anc);
for(int i=;i<edge[now].size();i++)
{
int temp=edge[now][i];
if(temp!=par[now] && temp!=son[now]) dfs2(temp,temp);
}
} void update_chain(int a,int b,int x)
{
while(tp[a]!=tp[b])
{
if(dep[tp[a]]<dep[tp[b]]) swap(a,b);
update(dfsx[tp[a]],dfsx[a],,,n,x);
a=par[tp[a]];
}
if(dep[a]<dep[b]) swap(a,b);
update(dfsx[b],dfsx[a],,,n,x);
} int query_chain(int a,int b)
{
int sum=;
while(tp[a]!=tp[b])
{
if(dep[tp[a]]<dep[tp[b]]) swap(a,b);
sum+=query(dfsx[tp[a]],dfsx[a],,,n);
if(getcol(dfsx[tp[a]],,,n)==getcol(dfsx[par[tp[a]]],,,n)) sum--;
a=par[tp[a]];
}
if(dep[a]<dep[b]) swap(a,b);
sum+=query(dfsx[b],dfsx[a],,,n);
return sum;
} void work()
{
dfs1(,-,);
dfs2(,);
build(,n);
char s[];
int a,b,c;
while(m--)
{
scanf("%s",s);
if(s[]=='Q')
{
scanf("%d%d",&a,&b);
printf("%d\n",query_chain(a,b));
}
else
{
scanf("%d%d%d",&a,&b,&c);
update_chain(a,b,c);
}
}
} int main()
{
read();
work();
}
BZOJ 2243 [SDOI2011]染色:树剖【维护路径上颜色段】的更多相关文章
- BZOJ 2243: [SDOI2011]染色 (树剖+线段树)
树链剖分后两个区间合并的时候就判一下相交颜色是否相同来算颜色段数就行了. CODE #include <vector> #include <queue> #include &l ...
- BZOJ 2243: [SDOI2011]染色 [树链剖分]
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6651 Solved: 2432[Submit][Status ...
- Bzoj 2243: [SDOI2011]染色 树链剖分,LCT,动态树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 5020 Solved: 1872[Submit][Status ...
- BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...
- BZOJ 2243: [SDOI2011]染色 树链剖分+线段树区间合并
2243: [SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数 ...
- BZOJ 2243 [SDOI2011]染色 (树链剖分)(线段树区间修改)
[SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6870 Solved: 2546[Submit][Status][Disc ...
- [bzoj 2243]: [SDOI2011]染色 [树链剖分][线段树]
Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“ ...
- BZOJ 2243: [SDOI2011]染色 (树链剖分+线段树合并)
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2243 树链剖分的点剖分+线段树.漏了一个小地方,调了一下午...... 还是要细心啊! 结 ...
- bzoj 2243 [SDOI2011]染色(树链剖分,线段树)
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4637 Solved: 1726[Submit][Status ...
随机推荐
- setpgid()
#include<unistd.h> int setpgid(pid_t pid,pid_t pgid); 函数作用:将pid进程的进程组ID设置成pgid,创建一个新进程组或加入一个已存 ...
- Redis源码阅读-Adlist双向链表
Redis源码阅读-链表部分- 链表数据结构在Adlist.h Adlist.c Redis的链表是双向链表,内部定义了一个迭代器. 双向链表的函数主要是链表创建.删除.节点插入.头插入.尾插入. ...
- 安装Struts2 类库
现在,如果一切正常,那么你可以继续设置您的Struts 2框架.以下是简单的步骤,下载并安装在机器上Struts2. 请选择是否要安装Hibernate在Windows或Unix,然后继续进行下一个步 ...
- Cobbler部署之FAQ处理
Cobbler报错处理 通过cobbler check检查出现的报错 红色标注为报错关键信息 9.1 报错一 # cobbler check httpd does not appear to be r ...
- Android Studio 2.0 稳定版新特性介绍
Android Studio 2.0 最终迎来了稳定版本号,喜大普奔. 以下这篇文章是2.0新特性的一些简介. 假设想看具体内容请看这里<Android Studio有用指南> 文章转自这 ...
- 【BZOJ3743】[Coci2015]Kamp 树形DP
[BZOJ3743][Coci2015]Kamp Description 一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的. 有K个人(分布在K个不同的点)要集中到一个点举 ...
- 【BZOJ2728】[HNOI2012]与非 并查集+数位DP
[BZOJ2728][HNOI2012]与非 Description Input 输入文件第一行是用空格隔开的四个正整数N,K,L和R,接下来的一行是N个非负整数A1,A2……AN,其含义如上所述. ...
- 记录-spring MultipartFile 文件上传
注意:以下上传和下载方法未必完全正确,不同浏览器效果不同,建议不要使用IE /** * 简单的文件上传 * @author:qiuchen * @createTime:2012-6-19 * @par ...
- android菜鸟学习笔记20----Android数据存储(四))Android数据库操作
Android内置了一个名为SQLite的关系型数据库,这是一款轻量型的数据库,操作十分简便.SQLite与别的数据库不同的是,它没有数据类型.可以保存任何类型的数据到你所想要保存的任何表的任何列中. ...
- plsql 详细安装及汉化步骤
方法/步骤 双击运行plsqldev715 安装完成后我们装中文补丁: 双击运行‘Chinese’应用程序 找到PLSQL的安装目录添加进来 中文补丁安装完成后我们需要进行orcl的配置,配置好才 ...