LuoguP5327 [ZJOI2019]语言 线段树合并+树链求并

比较好的一道数据结构题.    

对于 $i$,我们希望求出所有经过 $i$ 号点的路径所构成的树链之并.    

考虑一个求解树链的并的经典做法就是 $\sum_{i=1}^{n} dep[i]-\sum_{i=2}^{n} dep[LCA(i,i-1)]$.    

这里要求所有点都要按照 $dfs$ 序排好.  

那么这道题中我们就基于 DFS 序对每个点建立动态开点线段树.     

加入一条路径就是在 $x,y$ 处添加 $(x,y)$,然后在 $fa[lca]$ 处将这 4 个点再都删掉.    

儿子向父亲合并的时候直接用线段树合并就行.  

pushup 的时候维护:$(s,t,f,si)$ 分别表示区间最靠左/右的节点编号,区间树链之并长度,以及叶节点开的桶.     

用 $RMQ-O(1)$ 求 $LCA$ 可做到 $O(n \log n)$.  

代码: 

#include 
#include 
#include 
#include 
#define N 100009  
#define ll long long
#define pb push_back
#define lson s[x].ls 
#define rson s[x].rs   
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
ll ans; 
int n,m,edges,tim,tot;  
vectorADD[N],DEL[N];  
int hd[N],to[N<<1],nex[N<<1],rt[N]; 
int fa[N],dfn[N],seq[20][N<<1],dep[N],Log[N<<1]; 
void add(int u,int v) {
    nex[++edges]=hd[u]; 
    hd[u]=edges,to[edges]=v;  
}    
void dfs(int x,int ff) {
    dep[x]=dep[ff]+1;  
    fa[x]=ff,dfn[x]=++tim,seq[0][tim]=x;     
    for(int i=hd[x];i;i=nex[i]) {
        int y=to[i]; 
        if(y==ff) continue;  
        dfs(y,x);      
        seq[0][++tim]=x;          
    }
}
void RMQ() {
    Log[1]=0; 
    for(int i=2;i<=2*n;++i) {
        Log[i]=Log[i>>1]+1;  
    }
    for(int i=1;(1<y) swap(x,y);  
    int p=Log[y-x+1];     
    return dep[seq[p][x]]>1;   
    if(p<=mid)  {
        update(lson,l,mid,p,v);  
    }
    else {
        update(rson,mid+1,r,p,v); 
    }
    pushup(x);   
}
int merge(int l,int r,int x,int y) {
    if(!x||!y) {
        return x+y;  
    }   
    int now=++tot,mid=(l+r)>>1;    
    if(l==r) {
        s[now].si=s[x].si+s[y].si;   
        s[now].s=s[x].s|s[y].s;   
        s[now].t=s[x].t|s[y].t;  
        s[now].f=s[x].f|s[y].f;   
        return now;        
    }
    s[now].ls=merge(l,mid,s[x].ls,s[y].ls); 
    s[now].rs=merge(mid+1,r,s[x].rs,s[y].rs);  
    pushup(now); 
    return now;    
} 
void solve(int x,int ff) {
    for(int i=hd[x];i;i=nex[i]) {
        int y=to[i]; 
        if(y==ff) continue;  
        solve(y,x);  
        rt[x]=merge(1,n<<1,rt[x],rt[y]);  
    }     
    for(int i=0;i>1);   
    return 0;
}

  

你可能感兴趣的:(LuoguP5327 [ZJOI2019]语言 线段树合并+树链求并)