• #2689. 异或树(tree)


    题目描述

    `LYK` 在森林里找到了一棵树。这棵树非常神奇,每条边都有其边权,每个点也有它的点权 $a_i$ 。我们令 $dis(i,j)$ 表示点 $i$ 与点 $j$ 之间的最短路的距离。

    `LYK` 每次选择树上两个点 $x,y(x<y)$ ,它将会得到 $(a_x wedge a_y)dis(x,y)$ 的金币(其中 $wedge$ 表示异或)。它认为这个值太容易计算了,于是它想把所有关于 $x,y$ 的点对( $frac{n(n-1)}{2}$ 对)能得到的金币都求出来,并计算它能得到的金币总和。

    这时人群中跳出一个熊孩子来搞破坏,它每次会修改 `LYK` 的树中的某个点权。 `LYK` 想知道每次被搞破坏后它能得到的金币总和。

    题解

    考虑拆位,即我们计算每一位 $x$ 为 $0$ 且 $y$ 为 $1$ 的 $dis(x,y)$ 的总和。

    看到 $dis$ 可以想到点分治,题目又有点类似强制在线,所以我们考虑动态点分,每个点分中心维护每一位为 $0/1$ 的个数和 $dis$ 的总和,记得在上一级的点分中心更新的时候要在这一级上进行容斥即可。

    效率: $O(14(n+q)logn)$ 。

    代码

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int N=30005,N2=N<<1;
    int n,a[N],hd[N],V[N2],nx[N2],W[N2],sz[N],son[N];
    int f[N2][16],Lg[N2],c,d[N],e[N],up[N],o,rt,t,q;
    bool vis[N];LL s1[2][14][N2],s2[2][14][N2],ans;
    void add(int u,int v,int w){
        nx[++t]=hd[u];V[hd[u]=t]=v;W[t]=w;
    }
    void Sz(int u,int fr){
        sz[u]=1;
        for (int v,i=hd[u];i;i=nx[i])
            if (!vis[v=V[i]] && V[i]!=fr)
                Sz(v,u),sz[u]+=sz[v];
    }
    void Rt(int u,int fr){
        son[u]=o-sz[u];
        for (int v,i=hd[u];i;i=nx[i])
            if (!vis[v=V[i]] && V[i]!=fr)
                Rt(v,u),son[u]=max(son[u],sz[v]);
        if (son[rt]>son[u]) rt=u;
    }
    void work(int u,int fr){
        Sz(u,0);o=sz[u];rt=0;
        Rt(u,0);up[rt]=fr;vis[fr=rt]=1;
        for (int i=hd[rt];i;i=nx[i])
            if (!vis[V[i]]) work(V[i],fr);
    }
    void dfs(int u,int fr){
        f[e[u]=++c][0]=d[u];
        for (int i=hd[u],v;i;i=nx[i])
            if ((v=V[i])!=fr)
                d[v]=d[u]+W[i],
                dfs(v,u),f[++c][0]=d[u];
    }
    int lca(int l,int r){
        if (l>r) swap(l,r);int i=Lg[r-l+1];
        return min(f[l][i],f[r-(1<<i)+1][i]);
    }
    int dis(int u,int v){
        return d[u]+d[v]-(lca(e[u],e[v])<<1);
    }
    void Upd(int x,int u,int v){
        int y=dis(x,u>n?up[u-n]:u);
        for (int i=0;i<14;i++)
            s1[(a[x]>>i)&1][i][u]+=(1ll<<i)*v*y,
            s2[(a[x]>>i)&1][i][u]+=v;
    }
    void upd(int u,int v){
        Upd(u,u,v);
        for (int x=u;up[u];u=up[u])
            Upd(x,up[u],v),Upd(x,u+n,-v);
    }
    void Qry(int x,int u,int v){
        int y=dis(x,u>n?up[u-n]:u);
        for (int w,i=0;i<14;i++)
            w=(a[x]>>i)&1,
            ans+=(1ll<<i)*v*s2[!w][i][u]*y+s1[!w][i][u]*v;
    }
    void qry(int u,int v){
        Qry(u,u,v);
        for (int x=u;up[u];u=up[u])
            Qry(x,up[u],v),Qry(x,u+n,v);
    }
    int main(){
        cin>>n;son[0]=1e9;
        for (int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for (int u,v,w,i=1;i<n;i++)
            scanf("%d%d%d",&u,&v,&w),
            add(u,v,w),add(v,u,w);
        work(1,0);dfs(1,0);
        for (int i=2;i<=c;i++) Lg[i]=Lg[i>>1]+1;
        for (int i=c;i;i--)
            for (int j=1;i+(1<<j)<=c+1;j++)
                f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
        for (int i=1;i<=n;i++)
            qry(i,1),upd(i,1);cin>>q;
        for (int x,y;q--;)
            scanf("%d%d",&x,&y),upd(x,-1),qry(x,-1),
            a[x]=y,qry(x,1),upd(x,1),printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    Android中通过intent打开浏览器到指定网页
    iOS真机调试
    Autodesk Infrastructure Modeler(AIM)冉冉升起的新星
    IKVM.NET_07_用户指南_IKVM.NET 字节码编译器(ikvmc.exe)
    我们——程序员应该关注,功能?设计?
    系统集成的困境
    系统服务_时间同步服务器
    ASP.NET_ASP.NET 缓存Cache
    IKVM.NET_第五篇_用户指南_安装
    IKVM.NET_第四篇_用户指南_概述
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/12389715.html
Copyright © 2020-2023  润新知