【xsy2913】 enos 动态dp

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

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

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

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

数据范围:$n,m≤10^5$。

此题一眼动态dp

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

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

显然,$f[u]=1+sum_{v∈son[u],col[u]=col[v]} f[v]$

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

下面考虑动态dp

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

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

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

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

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

首先考虑查询$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
",Query(x,querycol(1,id[x])));
162         else{
163             scanf("%d%d",&y,&col);
164             Updata(x,y,col,1);
165         }
166     }
167 }
原文地址:https://www.cnblogs.com/xiefengze1/p/10536663.html