【xsy2913】 enos 动态dp

题目大意:给你一棵 n个点 以 1为根 的树,每个点有0,1,2三种颜色之一,初始时整棵树的颜色均为 0

m 次操作, 每次操作形如:

1 x y c : 将 xy的路径上的点全部改为颜色C

2 x : 询问 x 所在的同色连通块大小

数据范围:n,m105

 

 

此题一眼动态dp

首先我们先列出正常的dp式子

f[u]表示以u为根的子树中,u所在的同色联通块大小

显然,f[u]=1+vson[u],col[u]=col[v]f[v]

若需要输出某个点x的答案,我们需要输出f[y],其中y是满足xy颜色相同的最远祖先。

 

下面考虑动态dp

我们用树链剖分把原树剖成若干条链,每条链用线段树维护,对于线段树每个节点,我们维护七个变量:

设线段树某个节点表示的区间为[lk,rk],这个区间中对应原树的节点编号为rec[lk],rec[lk+1]....rec[rk]

sum[i]0i2)表示当前的区间中,颜色为i的节点的个数。

cnt[i]0i2)表示原树中所有与rec[lk....rk]相连的,且颜色为i的轻儿子中,满足以这些儿子为根的子树中,这些点所在的同色联通快大小之和。

tag为涂色标记,表示区间[lk,rk]中的点是否被刷成了同一个颜色。

 

首先考虑查询x所在的联通块大小,令id[x]表示节点x在原树中的dfs序,col[x]表示第x个节点当前的颜色,top[x]表示x所在重链链顶节点编号

我们首先在x所在的重链上,查询出LR,满足LxR,且节点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 }
复制代码
posted @   AlphaInf  阅读(292)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示