【xsy2913】 enos 动态dp
题目大意:给你一棵 n个点 以 1为根 的树,每个点有0,1,2三种颜色之一,初始时整棵树的颜色均为 0。
m 次操作, 每次操作形如:
1 x y c : 将 x到y的路径上的点全部改为颜色C
2 x : 询问 x 所在的同色连通块大小
数据范围:n,m≤105。
此题一眼动态dp
首先我们先列出正常的dp式子
设f[u]表示以u为根的子树中,u所在的同色联通块大小
显然,f[u]=1+∑v∈son[u],col[u]=col[v]f[v]
若需要输出某个点x的答案,我们需要输出f[y],其中y是满足x至y颜色相同的最远祖先。
下面考虑动态dp
我们用树链剖分把原树剖成若干条链,每条链用线段树维护,对于线段树每个节点,我们维护七个变量:
设线段树某个节点表示的区间为[lk,rk],这个区间中对应原树的节点编号为rec[lk],rec[lk+1]....rec[rk]。
sum[i](0≤i≤2)表示当前的区间中,颜色为i的节点的个数。
cnt[i](0≤i≤2)表示原树中所有与rec[lk....rk]相连的,且颜色为i的轻儿子中,满足以这些儿子为根的子树中,这些点所在的同色联通快大小之和。
tag为涂色标记,表示区间[lk,rk]中的点是否被刷成了同一个颜色。
首先考虑查询x所在的联通块大小,令id[x]表示节点x在原树中的dfs序,col[x]表示第x个节点当前的颜色,top[x]表示x所在重链链顶节点编号
我们首先在x所在的重链上,查询出L和R,满足L≤x≤R,且节点rec[L],rec[L+1]...rec[x]...rec[R]的颜色是一样的,答案显然要累加上这一段节点的贡献。
查询这部分的贡献我们可以在线段树上向x两侧二分查找即可,详见代码。
然后我们需要加上所有与区间[L,R]相连的轻链上的贡献。查询这部分信息直接在线段树上将cnt的信息累加一下就可以了。
我们目前只统计了x所在重链的情况,上方的重链我们尚未统计
若rec[L]=top[x],说明x所在的联通块可能会与top[x]上方的节点相连,这个时候需要去统计下上方的贡献。
否则直接退出就可以了。
下面考虑修改操作
我们按照正常树剖的操作来处理,假设我们当前要更改[x′,x]的颜色
我们显然现在线段树上对这一个区间更新一下颜色。
然后我们发现,这么操作的话,以top[x]为根的树种,top[x]所在同色联通块大小可能会变,这个时候我们需要重新求一下“以top[x]为根,top[x]所在同色联通块大小”,并将这个值上传更新上一条链的cnt值。
(详见代码)
这里有一个要注意的地方,更新区间的颜色可以只更新到lca(x,y),但是更新联通块大小必须更新到根(场上错在这里)
然后就没有了
注意细节!
1 #include<bits/stdc++.h> 2 #define M 100005 3 #define mid ((a[x].l+a[x].r)>>1) 4 using namespace std; 5 6 struct seg{int l,r,tag,sum[3],cnt[3];}a[M<<2]={0}; 7 void build(int x,int l,int r){ 8 a[x].l=l; a[x].r=r; a[x].tag=-1; if(l==r) return; 9 build(x<<1,l,mid); build(x<<1|1,mid+1,r); 10 } 11 void upd(int x,int k){ 12 a[x].sum[0]=a[x].sum[1]=a[x].sum[2]=0; 13 a[x].tag=k; a[x].sum[k]=a[x].r-a[x].l+1; 14 } 15 void pushdown(int x){ 16 if(a[x].tag!=-1) upd(x<<1,a[x].tag),upd(x<<1|1,a[x].tag); 17 a[x].tag=-1; 18 } 19 void pushup(int x){ 20 for(int i=0;i<3;i++){ 21 a[x].sum[i]=a[x<<1].sum[i]+a[x<<1|1].sum[i]; 22 a[x].cnt[i]=a[x<<1].cnt[i]+a[x<<1|1].cnt[i]; 23 } 24 } 25 void updatacol(int x,int l,int r,int col){ 26 if(l<=a[x].l&&a[x].r<=r) return upd(x,col); 27 pushdown(x); 28 if(l<=mid) updatacol(x<<1,l,r,col); 29 if(mid<r) updatacol(x<<1|1,l,r,col); 30 pushup(x); 31 } 32 void updatacnt(int x,int id,int col,int val){ 33 if(a[x].l==a[x].r)return void(a[x].cnt[col]+=val); 34 pushdown(x); 35 if(id<=mid) updatacnt(x<<1,id,col,val); 36 else updatacnt(x<<1|1,id,col,val); 37 pushup(x); 38 } 39 int querycnt(int x,int l,int r,int col){ 40 if(l<=a[x].l&&a[x].r<=r) return a[x].cnt[col]; 41 pushdown(x); int res=0; 42 if(l<=mid) res+=querycnt(x<<1,l,r,col); 43 if(mid<r) res+=querycnt(x<<1|1,l,r,col); 44 return res; 45 } 46 int querycol(int x,int id){ 47 if(a[x].l==a[x].r){ 48 if(a[x].sum[0]) return 0; 49 if(a[x].sum[1]) return 1; 50 return 2; 51 } 52 pushdown(x); 53 if(id<=mid) return querycol(x<<1,id); 54 return querycol(x<<1|1,id); 55 } 56 int queryUP(int x,int l,int r,int col){ 57 if(l<=a[x].l&&a[x].r<=r){ 58 if(a[x].sum[col]==a[x].r-a[x].l+1) return a[x].l; 59 } 60 if(a[x].l==a[x].r) return 0; 61 pushdown(x); 62 if(mid<r){ 63 int res=queryUP(x<<1|1,l,r,col); 64 if(res!=mid+1) return res; 65 int res2=0; 66 if(l<=mid) res2=queryUP(x<<1,l,r,col); 67 if(res2) return res2; 68 return res; 69 } 70 return queryUP(x<<1,l,r,col); 71 } 72 int queryDN(int x,int l,int r,int col){ 73 if(l<=a[x].l&&a[x].r<=r){ 74 if(a[x].sum[col]==a[x].r-a[x].l+1) return a[x].r; 75 } 76 if(a[x].l==a[x].r) return 0; 77 pushdown(x); 78 if(l<=mid){ 79 int res=queryDN(x<<1,l,r,col); 80 if(res!=mid) return res; 81 int res2=0; 82 if(mid<r) res2=queryDN(x<<1|1,l,r,col); 83 if(res2) return res2; 84 return res; 85 } 86 return queryDN(x<<1|1,l,r,col); 87 } 88 89 struct edge{int u,next;}e[M]={0}; int head[M]={0},use=0; 90 void add(int x,int y){use++;e[use].u=y;e[use].next=head[x];head[x]=use;} 91 int fa[M]={0},id[M]={0},siz[M]={0},son[M]={0},dep[M]={0},top[M]={0},dn[M]={0},t=0,n,m; 92 int last[M]={0},rec[M]={0}; 93 94 void dfs(int x){ 95 siz[x]=1; 96 for(int i=head[x];i;i=e[i].next){ 97 fa[e[i].u]=x; dep[e[i].u]=dep[x]+1; 98 dfs(e[i].u); 99 siz[x]+=siz[e[i].u]; 100 if(siz[son[x]]<siz[e[i].u]) son[x]=e[i].u; 101 } 102 } 103 void dfs(int x,int Top){ 104 top[x]=Top; id[x]=++t; rec[t]=x; 105 if(son[x]){ 106 dfs(son[x],Top); 107 dn[x]=dn[son[x]]; 108 }else{ 109 updatacol(1,id[Top],id[x],0); 110 dn[x]=x; 111 } 112 for(int i=head[x];i;i=e[i].next) if(e[i].u!=son[x]){ 113 dfs(e[i].u,e[i].u); 114 updatacnt(1,id[x],0,last[e[i].u]=siz[e[i].u]); 115 } 116 } 117 118 int Query(int x,int col){ 119 if(!x) return 0; 120 int l=id[top[x]],r=id[dn[x]]; 121 int L=queryUP(1,l,id[x],col); 122 int R=queryDN(1,id[x],r,col); 123 int res=(R-L+1)+querycnt(1,L,R,col); 124 if(rec[L]==top[x]&&fa[top[x]]&&querycol(1,id[fa[top[x]]])==col) 125 return Query(fa[top[x]],col); 126 return res; 127 } 128 129 void Updata(int x,int y,int col,int chg){ 130 if(!x) return; 131 int Lastcol; 132 if(top[x]==top[y]){ 133 if(dep[x]<dep[y]) swap(x,y); 134 Lastcol=querycol(1,id[top[x]]); 135 if(chg) updatacol(1,id[y],id[x],col); 136 }else{ 137 if(dep[top[x]]<dep[top[y]]) swap(x,y); 138 Lastcol=querycol(1,id[top[x]]); 139 if(chg) updatacol(1,id[top[x]],id[x],col); 140 } 141 int Topcol=querycol(1,id[top[x]]); 142 int L=id[top[x]]; 143 int R=queryDN(1,L,id[dn[x]],Topcol); 144 int val=(R-L+1)+querycnt(1,L,R,Topcol); 145 if(fa[top[x]]){ 146 updatacnt(1,id[fa[top[x]]],Lastcol,-last[top[x]]); 147 updatacnt(1,id[fa[top[x]]],Topcol,val); 148 } 149 last[top[x]]=val; 150 if(top[x]!=top[y]) Updata(fa[top[x]],y,col,1); 151 else Updata(fa[top[x]],fa[top[x]],col,0); 152 } 153 154 int main(){ 155 scanf("%d%d",&n,&m); 156 build(1,1,n); 157 for(int i=2,x;i<=n;i++) scanf("%d",&x),add(x,i); 158 dfs(1); dfs(1,1); 159 while(m--){ 160 int op,x,y,col; scanf("%d%d",&op,&x); 161 if(op==2) printf("%d\n",Query(x,querycol(1,id[x]))); 162 else{ 163 scanf("%d%d",&y,&col); 164 Updata(x,y,col,1); 165 } 166 } 167 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!