JZOJ5783. 【省选模拟2018.8.8】树

题目

这里写图片描述
这里写图片描述

题目大意

给定一棵树,每个点都有一个权值,
现在有三种操作,换根,给一个子树里面的所有点加一个值,查询子树内的权值和。

题解

先看没有换根操作,这个就很简单了,
dfs序加上线段树,轻松解决。

再来看看多了换根的操作,
换了根之后,它的子树与在没有换根之前,也就是1为根有什么区别,
分类讨论一下,
假设这个节点x是属于root的子树,那么它的子树根原来的是一模一样的,
如果这个节点在root到根的路径上面,它的子树就变为正课树减去路径上面它的下一个点。
剩下的情况,子树还是没有变。

这样看来,无论换根与否,都只是涉及到整棵子树的,所以也只会用到线段树。
现在就是要考虑在换根之后,如何求lca了。
手玩一下就可以得出结论,
如果要求x,y,在root下的lca,那么就求x,y的,x,root的,y,root的,也就是他们两两之间的,在以1为根的lca,然后在这三个点之中,选出深度最大的,那么这个就在root下的lca。

code

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#define ll long long
#define ls (x<<1)
#define rs (x<<1|1)
#define N 500003
#define P putchar
#define G getchar
using namespace std;
char ch;
void read(int &n)
{
    n=0;
    ch=G();
    while((ch<'0' || ch>'9') && ch!='-')ch=G();
    ll w=1;
    if(ch=='-')w=-1,ch=G();
    while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
    n*=w;
}

int n,m,x,y,z,cz,root,_2[20];
int nxt[N*2],to[N*2],lst[N],fa[N],dep[N],tot,w[N];
ll v[N],si,s[N*4],lazy[N*4],ops,ans;
int id[N],sz[N],now,opl,opr,opx,rank[N],f[19][N],t;

void work(int x,int l,int r)
{
    if(opl<=l && r<=opr)
    {
        if(opx==1)s[x]+=ops*(r-l+1),lazy[x]+=ops;
            else ops+=s[x];
        return;
    }
    int m=(l+r)>>1;
    if(lazy[x])
    {
        lazy[ls]+=lazy[x];
        lazy[rs]+=lazy[x];
        s[ls]+=lazy[x]*(m-l+1);
        s[rs]+=lazy[x]*(r-m);
        lazy[x]=0;
    }
    if(opl<=m)work(ls,l,m);
    if(m<opr)work(rs,m+1,r);
    s[x]=s[ls]+s[rs];
}

void pre(int x,int l,int r)
{
    if(l==r)
    {
        s[x]=w[rank[l]];
        return;
    }
    int m=(l+r)>>1;
    pre(ls,l,m);
    pre(rs,m+1,r);
    s[x]=s[ls]+s[rs];
}

void dfs(int x)
{
    id[x]=++now;
    dep[x]=dep[fa[x]]+1;
    v[x]=w[x];
    for(int i=lst[x];i;i=nxt[i])
        if(to[i]!=fa[x])
        {
            fa[to[i]]=x;
            dfs(to[i]);
            v[x]+=v[to[i]];
        }
    sz[x]=now;
}

void ins(int x,int y)
{
    nxt[++tot]=lst[x];
    to[tot]=y;
    lst[x]=tot;
}

void dfs(int x,int y)
{
    v[x]=w[x]=w[x]+y;si++;
    for(int i=lst[x];i;i=nxt[i])
        if(to[i]!=fa[x])
        {
            dfs(to[i],y);
            v[x]+=v[to[i]];
        }
}

int lca(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    for(int j=18;j>=0;j--)
        if(dep[f[j][x]]>=dep[y])x=f[j][x];
    if(x==y)return x;
    for(int j=18;j>=0;j--)
        if(f[j][x]!=f[j][y])x=f[j][x],y=f[j][y];
    return f[0][x];
}

int up(int x,int y)
{
    for(int j=18;j>=0;j--)
        if(y>=_2[j])y=y-_2[j],x=f[j][x];
    return x;
}

int main()
{
    _2[0]=1;
    for(int i=1;i<20;i++)
        _2[i]=_2[i-1]<<1;

    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);

    read(n);read(m);
    for(int i=1;i<=n;i++)
        read(w[i]);
    for(int i=1;i<n;i++)
        read(x),read(y),ins(x,y),ins(y,x);
    dfs(1);

    for(int i=1;i<=n;i++)
        rank[id[i]]=i;
    pre(1,1,n);
    for(int i=1;i<=n;i++)
        f[0][i]=fa[i];
    for(int j=1;j<19;j++)
        for(int i=1;i<=n;i++)
            f[j][i]=f[j-1][f[j-1][i]];
    for(int i=1;i<=m;i++)
    {
        read(cz);read(x);
        if(cz==1)root=x;else
        if(cz==2)
        {
            read(y);read(z);
            t=lca(x,y);
            now=lca(x,root);
            if(dep[t]<dep[now])t=now;
            now=lca(y,root);
            if(dep[t]<dep[now])t=now;

            if(t==root)
            {
                opx=1;ops=z;opl=id[1];opr=sz[1];
                work(1,1,n);
            }
            else
            if(lca(t,root)!=t)
            {
                opx=1;ops=z;opl=id[t];opr=sz[t];
                work(1,1,n);
            }
            else
            {
                now=up(root,dep[root]-dep[t]-1);
                opx=1;ops=z;opl=id[1];opr=sz[1];
                work(1,1,n);
                opx=1;ops=-z;opl=id[now];opr=sz[now];
                work(1,1,n);

            }
        }
        else
        {
            t=x;
            if(t==root)
            {
                opx=2;ops=0;opl=id[1];opr=sz[1];
                work(1,1,n);
                ans=ops;
            }
            else
            if(lca(t,root)!=t)
            {
                opx=2;ops=0;opl=id[t];opr=sz[t];
                work(1,1,n);
                ans=ops;
            }
            else
            {
                now=up(root,dep[root]-dep[t]-1);
                opx=2;ops=0;opl=id[1];opr=sz[1];
                work(1,1,n);
                ans=ops;
                opx=2;ops=0;opl=id[now];opr=sz[now];
                work(1,1,n);
                ans=ans-ops;

            }
            printf("%lld\n",ans);
        }
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/lijf2001/article/details/81516106