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

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

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

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

点我

#include
using namespace std;
#define fuck(x) cout<<#x<<"     "<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<= 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

点我

#include
using namespace std;
#define fuck(x) cout<<#x<<"     "<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'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<= 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"<>1;
        //fuck(mid);
        if(check(mid))
            ans=mid,high=mid-1;
        else
            low=mid+1;
    }
    printf("%d\n",ans);
    return 0;
}

 

你可能感兴趣的:(树上差分(点差分和边差分))