zoukankan      html  css  js  c++  java
  • 树上差分(点差分和边差分)

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

    点差分: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;
    }
    
  • 相关阅读:
    分层图最短路(DP思想) BZOJ2662 [BeiJing wc2012]冻结
    动态规划 BZOJ1925 地精部落
    线性DP SPOJ Mobile Service
    线性DP codevs2185 最长公共上升子序列
    数位DP POJ3208 Apocalypse Someday
    线性DP POJ3666 Making the Grade
    杨氏矩阵 线性DP? POJ2279 Mr.Young's Picture Permutations
    tarjan强连通分量 洛谷P1262 间谍网络
    树链剖分 BZOJ3589 动态树
    二分图 BZOJ4554 [Tjoi2016&Heoi2016]游戏
  • 原文地址:https://www.cnblogs.com/eason9906/p/11754752.html
Copyright © 2011-2022 走看看