• 【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 }
  • 相关阅读:
    HBase 异步查询导致的死锁和zookeeper通信中断问题追踪与总结[非技术]
    [读书笔记]代码整洁之道读书笔记
    HBase行锁与MVCC分析
    进程、线程、轻量级进程、协程和go中的Goroutine 那些事儿
    上周回顾 - 2012年11.26-12.4
    2012年一个屌丝程序员的学习总结:读书、户外、泡妞、习惯、母猪产后护理
    C#_WinForm接收命令行参数
    SQL常识
    集成.Net / Flex3 & FluorineFX — Part II: The Client
    DB2基本概念
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10536663.html
Copyright © 2020-2023  润新知