zoukankan      html  css  js  c++  java
  • 树链剖分

    复杂度nlog2n

    边权可以转化成点权 搞一个根 把边权给到边两端深度大的哪个点 这样处理要删一个点 要删的是lca(x,y)

    第一步

    处理出fa deep size son

    void dfs1(int u,int fa,int depth)    //当前节点、父节点、层次深度
    {
        f[u]=fa;
        d[u]=depth;
        size[u]=1;    //这个点本身size=1
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if(v==fa)
                continue;
            dfs1(v,u,depth+1);    //层次深度+1
            size[u]+=size[v];    //子节点的size已被处理,用它来更新父节点的size
            if(size[v]>size[son[u]])
                son[u]=v;    //选取size最大的作为重儿子
        }
    }
    //进入
    dfs1(root,0,1);

    第二步

    连接重链 处理出top dfn rk 注意先处理重链再处理轻链 保证了重链的dfn值连续

    void dfs2(int u,int t)    //当前节点、重链顶端
    {
        top[u]=t;
        id[u]=++cnt;    //标记dfs序
        rk[cnt]=u;    //序号cnt对应节点u
        if(!son[u])
            return;
        dfs2(son[u],t);
    /*我们选择优先进入重儿子来保证一条重链上各个节点dfs序连续,
    一个点和它的重儿子处于同一条重链,所以重儿子所在重链的顶端还是t*/
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if(v!=son[u]&&v!=f[u])
                dfs2(v,v);    //一个点位于轻链底端,那么它的top必然是它本身
        }
    }

    求lca步骤:

    如果两个是在一个重链上的(top相同) 直接选深度小的哪个为lca

    否则的话每次选两个节点中top深度深的哪个节点跳

    修改步骤:

    如果和lca有关的话因为dfn是连续的 就相当于在跳的过程中的每个区间都区间修改区间查询 复杂度是log2n

    如果是和子树有关的话 就只是和dfs序有关了 也是区间修改区间查询

    将所有未被任何一条树链经过的树边删除,那么剩下的点度数都不能超过22,否则必然非法。

    那么剩下的图每个连通块都只可能是链,是经典序列问题,把所有区间按左端点排序后单调栈判断即可。

    #include<cstdio>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
    const int N=100010;
    int n,m,i,x,y,g[N],v[N<<1],nxt[N<<1],ed;
    int f[N],son[N],size[N],top[N],d[N];
    int e[N][2];
    int tag[N];
    int deg[N];
    int G[N],V[N<<1],NXT[N<<1],ED;
    bool vis[N];
    int ge[N],vv[N],nxte[N],ee;
    void NIE(){
        puts("No");
        exit(0);
    }
    inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
    inline void adde(int x,int y){vv[++ee]=y;nxte[ee]=ge[x];ge[x]=ee;}
    void dfs(int x){
        d[x]=d[f[x]]+1;
        size[x]=1;
        for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
            f[v[i]]=x;
            dfs(v[i]);
            size[x]+=size[v[i]];
            if(size[v[i]]>size[son[x]])son[x]=v[i];
        }
    }
    void dfs2(int x,int y){
        top[x]=y;
        if(son[x])dfs2(son[x],y);
        for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]&&v[i]!=son[x])dfs2(v[i],v[i]);
    }
    inline void addedge(int x,int y){
        //printf("! %d %d
    ",x,y);
        deg[x]++;deg[y]++;
        V[++ED]=y;NXT[ED]=G[x];G[x]=ED;
        V[++ED]=x;NXT[ED]=G[y];G[y]=ED;
    }
    void dfs3(int x){
        for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
            dfs3(v[i]);
            tag[x]+=tag[v[i]];
        }
        if(x>1&&tag[x])addedge(x,f[x]);
    }
    inline int lca(int x,int y){
        while(top[x]!=top[y]){
            if(d[top[x]]<d[top[y]])swap(x,y);
            x=f[top[x]];
        }
        return d[x]<d[y]?x:y;
    }
    int q[N],pos[N];
    int all;
    struct Seg{
        int l,r;
    }seg[N],st[N];
    inline bool cmp(const Seg&a,const Seg&b){
        if(a.l!=b.l)return a.l<b.l;
        return a.r>b.r;
    }
    inline void append(int l,int r){
        if(l>r)swap(l,r);
        seg[++all].l=l;
        seg[all].r=r;
    }
    inline void check(){
        if(all<=1)return;
        sort(seg+1,seg+all+1,cmp);
        int i;
        int t=0;
        for(i=1;i<=all;i++){
            while(t){
                if(seg[i].r<=st[t].r)break;
                if(seg[i].l<=st[t].r)NIE();
                t--;
            }
            st[++t]=seg[i];
        }
    }
    inline void solve(int S){
        int cnt=0;
        int i,j;
        while(1){
            vis[S]=1;
            q[++cnt]=S;
            int t=0;
            for(i=G[S];i;i=NXT[i])if(!vis[V[i]]){
                t=V[i];
            }
            if(!t)break;
            S=t;
        }
        //for(i=1;i<=cnt;i++)printf("%d ",q[i]);puts("");
        for(i=1;i<=cnt;i++)pos[q[i]]=i;
        all=0;
        for(i=1;i<=cnt;i++){
            for(j=ge[q[i]];j;j=nxte[j]){
                append(pos[q[i]],pos[vv[j]]);
            }
        }
        check();
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(i=1;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
        dfs(1);
        dfs2(1,1);
        for(i=1;i<=m;i++){
            scanf("%d%d",&x,&y);
            e[i][0]=x,e[i][1]=y;
            int z=lca(x,y);
            tag[x]++;
            tag[y]++;
            tag[z]-=2;
            adde(x,y);
        }
        dfs3(1);
        for(i=1;i<=n;i++)if(deg[i]>2)NIE();
        for(i=1;i<=n;i++)if(deg[i]==1&&!vis[i])solve(i);
        puts("Yes");
    }
    View Code
  • 相关阅读:
    基于边缘计算网关的桥梁结构安全监测应用
    5G工业网关的边缘计算
    5G工业网关和5G工业路由器差异对比分析
    大型网站架构系列:消息队列(二)
    大型网站架构系列:分布式消息队列(一)
    [转]线程安全类的设计
    [转]runloop原理
    [转]深入理解RunLoop
    [转]iOS保持界面流畅的技巧和AsyncDisplay介绍
    [转]面试时如何优雅的谈论OC
  • 原文地址:https://www.cnblogs.com/Aragaki/p/9387548.html
Copyright © 2011-2022 走看看