题目连接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28982#problem/D

题意:给定一棵有n个节点的无根树及点权和m个操作,操作有2类:

1、将节点a到节点b路径上所有点都染成颜色c;

2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段);

分析:树链剖分将信息映射到线段树后,线段树则要维护区间的两个端点值,在区间合并时”左孩子的右端点“与“右孩子的左端点”相同时总数减一。。。

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <stack>
#include <vector>
#include <set>
#include <map>
#define LL long long
#define mod 10007
#define inf 0x3f3f3f3f
#define N 100010
#define FILL(a,b) (memset(a,b,sizeof(a)))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std; struct edge
{
int to,next;
edge(){}
edge(int to,int next):to(to),next(next){}
}e[N<<];
int head[N<<],tot;
int top[N];//top[v]表示v所在的重链的顶端节点
int fa[N];//父亲节点
int dep[N];//深度
int sz[N];//si[v]表示以v为根节点的子树的节点数
int son[N];//重儿子
int p[N];//p[v]表示v与其父亲节点的连边在线段树中的位置
int fp[N];//与p数组相反
int pos;//所有链构成的线段树总长度
int sum[N<<],col[N<<],lc[N<<],rc[N<<],a[N];
void addedge(int u,int v)
{
e[tot]=edge(v,head[u]);
head[u]=tot++;
}
void init()
{
tot=;FILL(head,-);
pos=;FILL(son,-);
}
void dfs(int u,int f,int d)
{
dep[u]=d;sz[u]=;fa[u]=f;
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].to;
if(v==f)continue;
dfs(v,u,d+);
sz[u]+=sz[v];
if(son[u]==-||sz[son[u]]<sz[v])son[u]=v;
}
}
void getpos(int u,int sp)
{
top[u]=sp;
p[u]=++pos;
fp[pos]=u;
if(son[u]==-)return;
getpos(son[u],sp);
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].to;
if(v!=son[u]&&v!=fa[u])
{
getpos(v,v);
}
}
}
void Pushup(int rt)
{
int ls=rt<<,rs=ls|;
sum[rt]=sum[ls]+sum[rs];
lc[rt]=lc[ls];rc[rt]=rc[rs];
if(lc[rs]==rc[ls])sum[rt]--;
}
void Pushdown(int rt)
{
if(col[rt])
{
int ls=rt<<,rs=ls|;
col[ls]=col[rs]=col[rt];
sum[ls]=sum[rs]=;
lc[ls]=rc[ls]=lc[rs]=rc[rs]=col[rt];
col[rt]=;
}
}
void build(int l,int r,int rt)
{
col[rt]=;
if(l==r)
{
lc[rt]=rc[rt]=a[fp[l]];
sum[rt]=;
return;
}
int m=(l+r)>>;
build(lson);
build(rson);
Pushup(rt);
}
void update(int L,int R,int c,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
lc[rt]=rc[rt]=c;
sum[rt]=;col[rt]=c;
return;
}
Pushdown(rt);
int m=(l+r)>>;
if(L<=m)update(L,R,c,lson);
if(m<R)update(L,R,c,rson);
Pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)return sum[rt];
Pushdown(rt);
int m=(l+r)>>;
int res=;
if(R<=m)res=query(L,R,lson);
else if(L>m)res=query(L,R,rson);
else
{
res=query(L,m,lson)+query(m+,R,rson);
if(rc[rt<<]==lc[rt<<|])res--;
}
return res;
}
int query1(int ps,int l,int r,int rt)
{
if(l==r)
return lc[rt];
Pushdown(rt);
int m=(l+r)>>;
if(ps<=m)return query1(ps,lson);
else return query1(ps,rson);
}
void update_tree(int u,int v,int c)
{
int fu=top[u],fv=top[v];
while(fu!=fv)
{
if(dep[fu]<dep[fv])
{
swap(fu,fv);
swap(u,v);
}
update(p[fu],p[u],c,,pos,);
u=fa[fu];fu=top[u];
}
if(dep[u]>dep[v])swap(u,v);
update(p[u],p[v],c,,pos,);
}
int lca(int u,int v)
{
int fu=top[u],fv=top[v];
int res=;
while(fu!=fv)
{
if(dep[fu]<dep[fv])
{
swap(fu,fv);
swap(u,v);
}
res+=query(p[fu],p[u],,pos,);
if(query1(p[fu],,pos,)==query1(p[fa[fu]],,pos,))res--;
u=fa[fu];fu=top[u];
}
if(dep[u]>dep[v])swap(u,v);
res+=query(p[u],p[v],,pos,);
return res;
}
int main()
{
int n,m,u,v,w;
char op[];
while(scanf("%d%d",&n,&m)>)
{
init();
for(int i=;i<=n;i++)scanf("%d",&a[i]);
for(int i=;i<n;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs(,,);
getpos(,);
build(,pos,);
while(m--)
{
scanf("%s",op);
if(op[]=='C')
{
scanf("%d%d%d",&u,&v,&w);
update_tree(u,v,w);
}
else
{
scanf("%d%d",&u,&v);
printf("%d\n",lca(u,v));
}
}
}
}

HYSBZ 2243(树链剖分)的更多相关文章

  1. HDU 3966 & POJ 3237 & HYSBZ 2243 树链剖分

    树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几 ...

  2. HYSBZ - 2243 树链剖分 + 线段树 处理树上颜色段数

    用线段树处理颜色段数 记录区间内的颜色段数,区间右端点的颜色,区间右端点的颜色. int tr[maxn<<2], lc[maxn<<2], rc[maxn<<2] ...

  3. bzoj 2243 树链剖分

    2013-11-19 16:21 原题传送门http://www.lydsy.com/JudgeOnline/problem.php?id=2243 树链剖分,用线段树记录该区间的颜色段数,左右端点颜 ...

  4. HYSBZ 1036树链剖分

    一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从 ...

  5. BZOJ 2243: [SDOI2011]染色 (树链剖分+线段树合并)

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2243 树链剖分的点剖分+线段树.漏了一个小地方,调了一下午...... 还是要细心啊! 结 ...

  6. HDU 3966 & POJ 3237 & HYSBZ 2243 & HRBUST 2064 树链剖分

    树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几 ...

  7. hysbz 2243 染色(树链剖分)

    题目链接:hysbz 2243 染色 题目大意:略. 解题思路:树链剖分+线段树的区间合并,可是区间合并比較简单,节点仅仅要记录左右端点的颜色就可以. #include <cstdio> ...

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

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

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

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

随机推荐

  1. python web with bottle and session (beaker)

    python web with bottle and session (beaker) http://icodesnip.com/snippet/python/python-web-with-bott ...

  2. 恭喜我开通了CSDN博客

    准备在这里写点东西,记录我的学习过程....

  3. JavaScript的原型继承

    JavaScript是一门面向对象的语言.在JavaScript中有一句很经典的话,万物皆对象.既然是面向对象的,那就有面向对象的三大特征:封装.继承.多态.这里讲的是JavaScript的继承,其他 ...

  4. 用 managedQuery() 时须要注意的一个陷阱

    Activity 里面提供了一个 managedQuery() 方法,依照 Android SDK 里面的说明,"the activity will manage its lifecycle ...

  5. MongoDB学习笔记(五) MongoDB文件存取操作

    由于MongoDB的文档结构为BJSON格式(BJSON全称:Binary JSON),而BJSON格式本身就支持保存二进制格式的数据,因此可以把文件的二进制格式的数据直接保存到MongoDB的文档结 ...

  6. 【ASP.NET Web API教程】5.5 ASP.NET Web API中的HTTP Cookie

    原文:[ASP.NET Web API教程]5.5 ASP.NET Web API中的HTTP Cookie 5.5 HTTP Cookies in ASP.NET Web API 5.5 ASP.N ...

  7. C 文件直接包含

    C 文件直接包含 有一部分代码很大,在很多函数中重复,可以直接写在另外的一个文件中,引用时直接包含.co.cpp两个函数都 包含c1.cxx. 点击(此处)折叠或打开 ////// co.cpp #i ...

  8. c++ 类名和enum时重复时要在类名前加class::

    c++ 类名和enum时重复时要在类名前加class:: 一些不好的习惯都是用小写,但又没有区分开token,看看代码再说,下面的代码是我在测试polymorphism时写的一部分,怎么也查不出,最后 ...

  9. Swift - 移除页面视图上的所有元素

    下面代码可以遍历移除页面视图上的所有元件 1 2 3 4 5 6 //清空所有子视图 func clearViews() {     for v in self.view.subviews as [U ...

  10. linux教程之一

    相信不少想学习linux的新手们正愁不知道看什么linux学习教程好,下面小编给大家收集和整理了几点比较重要的教程,供大家学习,如需想学习更多的话,可到wdlinux学堂寻找更多教程. 1. 忘记my ...