题意:树上每个结点有自己的颜色,支持两种操作:1.将u到v路径上的点颜色修改为c; 2.求u到v路径上有多少段不同的颜色。

分析:树剖之后用线段树维护区间颜色段数。区间查询区间修改。线段树结点中维护的有:段数,左端点颜色,右端点颜色和懒惰标记。

当区间合并时,若左孩子的右端点颜色和右孩子的左端点颜色相同,那么段数要减1。

区间修改时注意维护左右端点的颜色。

查询时若左右子区间连接处的颜色相同,段数减1。

在两点向一条链上寻找LCA时,每次查询都要保存该条链顶端的颜色,若该链顶端的颜色与下次查询的右端点相同,那么段数减1。

最后当两点回溯到一条链上之后,若两点对应各自上次回溯链顶端的颜色是否与查询区间的左右端点相同,则答案都需减1。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define lson rt<<1
#define rson rt<<1|1
#define Lson l,m,lson
#define Rson m+1,r,rson
typedef long long LL;
using namespace std;
const int maxn =1e5+5;
struct Edge{int to,next;
}E[2*maxn];
int n,head[maxn],tot;
int cnt,idx,size[maxn],fa[maxn],son[maxn],dep[maxn],top[maxn],id[maxn],rnk[maxn];
int a[maxn];
void init()
{   cnt=idx=tot=0;memset(head,-1,sizeof(head));dep[1]=0,fa[1]=1,size[0]=0;memset(son,0,sizeof(son));
}void AddEdge(int u,int v)
{E[tot] = (Edge){v,head[u]};head[u]=tot++;
}
void dfs1(int u)
{size[u]=1;for(int i=head[u];~i;i=E[i].next){int v=E[i].to;if(v!=fa[u]){fa[v]=u;dep[v]=dep[u]+1;dfs1(v);size[u]+=size[v];if(size[son[u]]<size[v]) son[u]=v;}}
}void dfs2(int u,int topu)
{top[u]= topu;id[u] = ++idx;rnk[idx] = u;if(!son[u]) return;dfs2(son[u],top[u]);for(int i=head[u];~i;i=E[i].next){int v=E[i].to;if(v!=fa[u]&&v!=son[u]) dfs2(v,v);}
}struct Node{int sum,add,lc,rc;
}tree[maxn<<2];
int Lc,Rc;
void pushup(int rt){                //区间合并tree[rt].sum = tree[lson].sum + tree[rson].sum; tree[rt].lc = tree[lson].lc;tree[rt].rc = tree[rson].rc;if(tree[lson].rc==tree[rson].lc)tree[rt].sum--;
}
void pushdown(int l,int r,int rt){if(tree[rt].add){tree[lson].add = tree[rson].add = 1;tree[lson].sum = tree[rson].sum = 1;tree[lson].lc = tree[lson].rc = tree[rt].lc;tree[rson].lc = tree[rson].rc = tree[rt].lc;tree[rt].add = 0;}
}void build(int l,int r,int rt)
{tree[rt].add = 0;if(l==r){tree[rt].sum = 1;tree[rt].lc = tree[rt].rc = a[rnk[l]];return;}int m = (l+r)>>1;build(Lson);build(Rson);pushup(rt);
}void update(int L,int R,int col,int l=1,int r=n,int rt=1){if(L<=l && R>=r){tree[rt].sum = tree[rt].add =1;tree[rt].lc = tree[rt].rc = col;return ;}pushdown(l,r,rt);int m =(l+r)>>1;if(L<=m) update(L,R,col,Lson);if(R>m) update(L,R,col,Rson);pushup(rt);
}int query(int L,int R,int l=1,int r=n,int rt=1){        //单点if(L==l) Lc = tree[rt].lc;if(R==r) Rc = tree[rt].rc;if(L<=l && R>=r)return tree[rt].sum;pushdown(l,r,rt);int m = (l+r)>>1 , ans=0; bool left = false;if(L<=m) {ans+=query(L,R,Lson);left = true;}if(R>m){ans +=query(L,R,Rson);if(left && tree[lson].rc ==tree[rson].lc) ans--;} pushup(rt);return ans;
}void CHANGE(int u,int v,int col)
{while(top[u]!=top[v]){if(dep[top[u]]<dep[top[v]]) swap(u,v);update(id[top[u]],id[u],col);u = fa[top[u]];    }if(dep[u]>dep[v]) swap(u,v);update(id[u],id[v],col);
}int Qsum(int u,int v)
{int c1=-1,c2=-1, ans=0;     //记录上条链最左侧的颜色while(top[u]!=top[v]){if(dep[top[u]]<dep[top[v]]){swap(u,v);swap(c1,c2);        }ans +=query(id[top[u]],id[u]);if(Rc == c1) ans--;c1 = Lc;u = fa[top[u]];}if(dep[u]>dep[v]){swap(u,v);swap(c1,c2);}ans += query(id[u],id[v]);if(Lc==c1) ans--;if(Rc==c2) ans--;return ans;
}int main()
{#ifndef ONLINE_JUDGEfreopen("in.txt","r",stdin);freopen("out.txt","w",stdout);#endifint m,q,u,v;char op[5];while(scanf("%d%d",&n,&m)==2){init();for(int i=1;i<=n;++i) scanf("%d",&a[i]);for(int i=1;i<n;++i){scanf("%d%d",&u,&v);AddEdge(u,v);AddEdge(v,u);}dfs1(1);dfs2(1,1);build(1,n,1);while(m--){scanf("%s",op);if(op[0]=='Q'){scanf("%d%d",&u,&v);printf("%d\n",Qsum(u,v));}else{int col;scanf("%d%d%d",&u,&v,&col);CHANGE(u,v,col);}}}return 0;
}

转载于:https://www.cnblogs.com/xiuwenli/p/9496846.html

HYSBZ - 2243 染色 (树链剖分+线段树)相关推荐

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

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

  2. P2486 [SDOI2011]染色(树链剖分+线段树)

    题干描述 输入描述 输出格式 对于每个询问操作,输出一行答案. 输入输出样例 输入 #1 复制 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. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 1153  Solved: 421 [Submit][Sta ...

  4. BZOJ3862Little Devil I——树链剖分+线段树

    题目大意: 给一棵树,每条边可能是黑色或白色(起始都是白色),有三种操作: 1.将u到v路径上所有边颜色翻转(黑->白,白->黑) 2.将只有一个点在u到v路径上的边颜色翻转 3.查询u到 ...

  5. CodeForces - 160D Edges in MST(思维+tarjan/树链剖分+线段树)

    题目链接:点击查看 题目大意:给出一张 n 个点 m 条边组成的带权无向图,现在对于每条边来说,确定一下其分类: 一定是最小生成树上的边 可能是最小生成树上的边 一定不是最小生成树的边 题目分析:两种 ...

  6. CodeForces - 609E Minimum spanning tree for each edge(最小生成树+树链剖分+线段树/树上倍增)

    题目链接:点击查看 题目大意:给出一张 n 个点和 m 条边组成的无向图,现在询问包含每一条边的最小生成树 题目分析:考虑求解次小生成树的思路: 求出最小生成树 ans 枚举每一条非树边 ( u , ...

  7. BZOJ4127Abs——树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

  8. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

  9. BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树

    题目描述 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中 的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才 ...

  10. YbtOJ-染色计划【树链剖分,线段树,tarjan】

    正题 题目大意 给出nnn个点的一棵树,每个点有个颜色aia_iai​,你每次可以选择一个颜色全部变成另一个颜色. 求最少多少次操作可以把一种颜色变成一个完整的连通块. 1≤k≤n≤2×1051\le ...

最新文章

  1. java12章_【有书共读】java核心技术卷1--第12章
  2. Ubuntu18.04 Numix
  3. STL之nth_element__寻找第n大的元素
  4. .NET异步方法调用的例子
  5. ant构建项目迁移到gradle_Gradle构建工具
  6. Hive的hiveserver2后台开启和关闭
  7. nodejs的安装和使用
  8. mysql query cache 查询缓存
  9. python计算坐标点欧式距离_计算机视觉课堂笔记-4
  10. Python调用shell命令方式
  11. 【IDEA】IDEA 格式化 代码技巧 idea 格式化 会加 <p> 标签
  12. 百度服务器保存信息多久,百度识图会保存图片在服务器上吗?
  13. 理解SVM的三重境界
  14. django.template.exceptions.TemplateSyntaxError: Invalid block tag on line 12: ‘static‘. Did you forg
  15. Android 高效安全加载图片
  16. 正确关闭迅雷右侧浏览器的方法
  17. 代写计算机ei,骗子 张爱荣 以代写代发EI期刊骗钱 钱收到后QQ不上,手机关机
  18. Cisco Packet Tracer 网络系统工程实训大作业【附网络拓扑图】
  19. python读取文本并且替换_python 读取文件并替换字段的实例
  20. 软件开发工程师 - 面试手册

热门文章

  1. 水滴石穿之子页面的滚动条设置 表格的固定高度宽度问题 复制带格式的文本...
  2. 链表讲解和基本操作练习附代码
  3. 如何在 macOS Monterey 中使用空间音频?
  4. ScreenFlow for mac(屏幕录像软件)
  5. 在Mac上如何更轻松的使用表情符号管理器
  6. 重装系统后mac语言怎么改成中文?
  7. upload-labs19记录
  8. spark2.1.0之源码分析——RPC客户端工厂TransportClientFactory
  9. Freemarker 最简单的例子程序
  10. Memcached · 最佳实践 · 热点 Key 问题解决方案