• 树上差分(点差分和边差分)


     因为准备学树剖于是又学了树差分。

    点差分:u至v路径上所有点点权+1,那么c[u]++,c[v]++,c[lca]--,c[fa[lca]]--,可以在多次更新树链的点之后,得到某点权值

    边差分:边差分的话要把边的权值存在他连着的儿子节点上,然后儿子节点的权值就是这条边的边权了,u至v路径上所有边的边权+1,那么c[u]++,c[v]++,c[lca]-=2,可以在多次更新树链之后,得到某边权值。

    点我

    #include<bits/stdc++.h>
    using namespace std;
    #define fuck(x) cout<<#x<<"     "<<x<<endl;
    const int maxn=5e4+10;
    int c[maxn];
    vector<int>g[maxn];
    
    int dep[maxn];            ///深度
    int fa[maxn][40];         /// fa[i][j] 表示 i 节点的第 2^j 的祖先
    int n,m;        ///其中 m = log(n * 1.0) / log(2.0);  n 为总数,编号为 1 ~ n;
    
    void dfs1(int s,int f){
        if(f != s) dep[s] = dep[f] + 1;
        for(int j = 0;j < g[s].size();j ++){
            int v = g[s][j];
            if(v != f){
                fa[v][0] = s;
                for(int i = 1;i <= m;i ++)
                    fa[v][i] = fa[fa[v][i-1]][i-1];
                dfs1(v,s);
            }
        }
    }
    
    int lca(int u,int v){				      ///u,v的最近公共祖先
        if(dep[u] < dep[v]) swap(u,v);      ///u 在下面
        int d = dep[u] - dep[v];
        for(int i = 0; (1 << i) <= d;i ++)      ///移动到相同深度
            if((1 << i) & d)            ///(1<<i)&f找到f化为2进制后1的位置,移动到相应的位置
                u = fa[u][i];               ///比如f=5(101),先移动2^0祖先,然后再移动2^2祖先
        if(u != v){
            for(int i = m;i >= 0;i --)
                if(fa[u][i] != fa[v][i])         ///从最大祖先开始,判断a,b祖先,是否相同
                    u = fa[u][i], v = fa[v][i];  ///如不相同,a b同时向上移动2^j
            u = fa[u][0];
        }
        return u;
    }
    
    void dfs2(int now,int fa)
    {
        for(int i=0;i<g[now].size();i++)
        {
            int v=g[now][i];
            if(v==fa) continue;
            dfs2(v,now);
            c[now]+=c[v];
        }
    }
    
    int main()
    {
        int k,maxx=0;
        scanf("%d%d",&n,&k);
        m=log(n * 1.0)/log(2.0);
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        dfs1(1,0);
        while(k--)
        {
            int x,y,tmp;
            scanf("%d%d",&x,&y);
            tmp=lca(x,y);
            c[x]++;c[y]++;c[tmp]--;c[fa[tmp][0]]--;
    
        }
        dfs2(1,0);
        for(int i=1;i<=n;i++){
            maxx=max(maxx,c[i]);
        }
        cout<<maxx<<endl;
        return 0;
    }
    

    点我

    #include<bits/stdc++.h>
    using namespace std;
    #define fuck(x) cout<<#x<<"     "<<x<<endl;
    const int maxn=3e5+10;
    struct node
    {
        int v,w,nxt;
        node(int v=0,int w=0,int nxt=0)
        {
            this->v=v;
            this->w=w;
            this->nxt=nxt;
        }
    }e[maxn<<1];
    struct myplan
    {
        int u,v,dis,lc;
        myplan(int u=0,int v=0,int dis=0,int lc=0)
        {
            this->u=u;
            this->v=v;
            this->dis=dis;
            this->lc=lc;
        }
        friend bool operator<(const myplan&mm,const myplan&gg)
        {
            return mm.dis<gg.dis;
        }
    }plan[maxn];
    int n,pn,m,maxe,pos,head[maxn],dis[maxn],fa[maxn][30],dep[maxn],lb[maxn],c[maxn];
    
    inline int read()
    
    {
    
        int x=0,f=1; char ch=getchar();
    
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    
        return x*f;
    
    }
    inline void dfs1(int u,int f,int di)
    {
        dep[u]=dep[f]+1;
        dis[u]=dis[f]+di;
        for(register int i=head[u];i;i=e[i].nxt){
            int v = e[i].v;
            if(v != f){
                fa[v][0] = u;
                for(register int j = 1;j <= m;++j)
                    fa[v][j] = fa[fa[v][j-1]][j-1];
                dfs1(v,u,e[i].w);
            }
        }
    }
    inline int lca(int u,int v){				      ///u,v的最近公共祖先
        if(dep[u] < dep[v]) swap(u,v);      ///u 在下面
        int d = dep[u] - dep[v];
        for(register int i = 0; (1 << i) <= d;++i)      ///移动到相同深度
            if((1 << i) & d)            ///(1<<i)&f找到f化为2进制后1的位置,移动到相应的位置
                u = fa[u][i];               ///比如f=5(101),先移动2^0祖先,然后再移动2^2祖先
    
        if(u != v){
            for(register int i = m;i >= 0;--i)
                if(fa[u][i] != fa[v][i])         ///从最大祖先开始,判断a,b祖先,是否相同
                    u = fa[u][i], v = fa[v][i];  ///如不相同,a b同时向上移动2^j
            u = fa[u][0];
        }
        return u;
    }
    inline void dfs2(int now,int f,int di)
    {
        for(register int i=head[now];i;i=e[i].nxt){
            int v=e[i].v,w=e[i].w;
            if(v==f) continue;
            dfs2(v,now,w);
            c[now]+=c[v];
        }
        if(c[now]==pn-pos+1)
            maxe=max(maxe,di);
    }
    inline bool check(int mid)
    {
        pos=upper_bound(lb+1,lb+pn+1,mid)-lb;
        if(pos==pn+1)
            return true;
        for(register int i=1;i<=n;i++) c[i]=0;
        for(register int i=pos;i<=pn;++i)
        {
            c[plan[i].u]++;c[plan[i].v]++;c[plan[i].lc]-=2;
        }
        maxe=-1;
        dfs2(1,0,0);
    //    if(mid==11)
    //    {
    //        cout<<"pos"<<pos<<endl;
    //        cout<<"maxe"<<maxe<<endl;
    //    }
        if(maxe==-1)
            return false;
        if(plan[pn].dis-maxe<=mid)
            return true;
        return false;
    }
    int main()
    {
        int cnt=0,low,high,mid,ans;
        n=read();
        pn=read();
        m=(log(n*1.0)/log(2.0))+1;
        for(register int i=1;i<n;++i)
        {
            int u,v,w;
            u=read();
            v=read();
            w=read();
            e[++cnt]=node(v,w,head[u]);
            head[u]=cnt;
            e[++cnt]=node(u,w,head[v]);
            head[v]=cnt;
        }
        dfs1(1,0,0);
        for(register int i=1;i<=pn;++i){
            plan[i].u=read();plan[i].v=read();plan[i].dis=dis[plan[i].u]+dis[plan[i].v]-2*dis[plan[i].lc=lca(plan[i].u,plan[i].v)];
        }
        sort(plan+1,plan+pn+1);
        for(int i=1;i<=pn;i++) lb[i]=plan[i].dis;
    //    cout<<"plan"<<endl;
    //    for(int i=1;i<=pn;i++) cout<<plan[i].u<<"  "<<plan[i].v<<"   "<<plan[i].dis<<endl;
    //    cout<<"end"<<endl;
        low=0,high=plan[pn].dis;
        while(low<=high)
        {
    
            mid=(low+high)>>1;
            //fuck(mid);
            if(check(mid))
                ans=mid,high=mid-1;
            else
                low=mid+1;
        }
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    001.云桌面整体解决方案实施
    Netty基础招式——ChannelHandler的最佳实践
    架构设计之数据分片
    Go是一门什么样的语言?
    Jenkins汉化配置
    Window安装构建神器Jenkins
    uni-app&H5&Android混合开发三 || uni-app调用Android原生方法的三种方式
    如何使用Hugging Face中的datasets
    关于torch.nn.LSTM()的输入和输出
    pytorch中的nn.CrossEntropyLoss()计算原理
  • 原文地址:https://www.cnblogs.com/eason9906/p/11754753.html
Copyright © 2020-2023  润新知