zoukankan      html  css  js  c++  java
  • HDU

    题意:给定一棵树,有点权a[],有边权。 现在有M次修改点权的操作,输出每次修改后,Σ(a[i]^a[j])*dis(i,j);

    思路:因为待修改,我们需要快速得到以及修改一个点到其他所有点的信息。 肯定就是动态点分治了啊。  

    而异或这个操作没有什么累加的性质,所以每一位拆开单独计算。 根据二进制位置和01区别,先建立14*2点分树。然后每次在同一位置,不同值的树上累加答案。

    因为计算dis的过程会重复很多次,所以可以用个dd数组,减少重复统计,然后就用1400ms变成 了960ms。

    #include<bits/stdc++.h>
    #define FOR() for(int i=Laxt[u];i;i=Next[i])
    #define ll long long
    #define rep(i,w,v) for(int i=w;i<=v;i++)
    using namespace std;
    const int maxn=30010;
    int Laxt[maxn],Next[maxn<<1],To[maxn<<1],Len[maxn<<1],cnt;
    int a[maxn],sz[maxn],son[maxn],dep[maxn];
    int Top[maxn],fa[maxn],Fa[maxn],vis[maxn],root,SZ;
    ll G[maxn][14][2],F[maxn][14][2],ans,dis[maxn]; //
    int num[maxn][14][2],mx;
    void init(int N)
    {
        cnt=0; rep(i,1,N) Laxt[i]=0;
        rep(i,1,N) vis[i]=0; ans=0;
        rep(i,1,N) rep(j,0,13) rep(k,0,1)
           G[i][j][k]=F[i][j][k]=num[i][j][k]=0;
    }
    void add(int u,int v,int len)
    {
        Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; Len[cnt]=len;
    }
    void dfs1(int u,int f)
    {
        sz[u]=1; dep[u]=dep[f]+1; fa[u]=f; son[u]=0;
        for(int i=Laxt[u];i;i=Next[i]){
            int v=To[i]; if(v==f) continue;
            dis[v]=dis[u]+Len[i];
            dfs1(v,u); sz[u]+=sz[v];
            if(sz[son[u]]<sz[v]) son[u]=v;
        }
    }
    void dfs2(int u,int tp)
    {
        Top[u]=tp;
        if(son[u]) dfs2(son[u],tp);
        FOR()
            if(To[i]!=fa[u]&&To[i]!=son[u])
                dfs2(To[i],To[i]);
    }
    
    int LCA(int u,int v)
    {
        while(Top[u]^Top[v]) dep[Top[u]]<dep[Top[v]]?v=fa[Top[v]]:u=fa[Top[u]];
        return dep[u]<dep[v]?u:v;
    }
    ll getdis(int u,int v){return dis[u]+dis[v]-2*dis[LCA(u,v)];}
    void Getroot(int u,int ff)
    {
        sz[u]=1;int ret=0;
        FOR(){
            int v=To[i];if(v==ff||vis[v])continue;
            Getroot(v,u);sz[u]+=sz[v];
            ret=max(ret,sz[v]);
        }
        ret=max(ret,SZ-sz[u]);
        if(ret<mx) mx=ret,root=u;
    }
    void DFS(int u,int ff)
    {
        vis[u]=true; Fa[u]=ff;
        FOR(){
            int v=To[i];if(vis[v])continue;
            mx=SZ=sz[v];
            Getroot(v,u);
            DFS(root,u);
        }
    }
    ll dd[maxn];
    void Modify(int u,int val,int opt)
    {
        int t;
        for(int j=u;Fa[j];j=Fa[j]) dd[j]=getdis(u,Fa[j]);
        rep(i,0,13){
            if(val&(1<<i)) t=1;
            else t=0;
            ans=ans+1LL*opt*(1<<i)*G[u][i][t^1];
            for(int j=u;Fa[j];j=Fa[j]){
                ll d=dd[j];
                ans=ans+1LL*opt*(1<<i)*(1LL*d*(num[Fa[j]][i][t^1]-num[j][i][t^1])+G[Fa[j]][i][t^1]-F[j][i][t^1]);
            }
        }
        rep(i,0,13){
            if(val&(1<<i)) t=1;
            else t=0;
            num[u][i][t]+=opt;
            for(int j=u;Fa[j];j=Fa[j]){
                ll d=dd[j];
                G[Fa[j]][i][t]+=d*opt;
                F[j][i][t]+=d*opt;
                num[Fa[j]][i][t]+=opt;
            }
        }
    }
    int main()
    {
        int N,Q,D,E,u,v,l;
        while(~scanf("%d",&N)){
            init(N);
            rep(i,1,N) scanf("%d",&a[i]);
            rep(i,1,N-1){
                scanf("%d%d%d",&u,&v,&l);
                add(u,v,l); add(v,u,l);
            }
            dfs1(1,0); dfs2(1,1);
            SZ=mx=N; Getroot(1,0);
            DFS(root,0);
            rep(i,1,N) Modify(i,a[i],1);
            scanf("%d",&Q);
            while(Q--){
                scanf("%d%d",&D,&E);
                Modify(D,a[D],-1);
                a[D]=E;
                Modify(D,a[D],1);
                printf("%lld
    ",ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    uva10422
    3259 spfa判断负环(邻接表)
    华东理工某ACMer总结
    POJ 1847 最短路径 垃圾水题可是坑爹多case问题初始化的锅
    HDU 1166 线段树基础题 基本模型
    用数组模拟邻接表
    优先队列
    POJ 3253 优先队列实现哈弗曼树
    POJ 3026 Kruskal+BFS
    POJ 1094差分约束系统拓扑排序
  • 原文地址:https://www.cnblogs.com/hua-dong/p/11214647.html
Copyright © 2011-2022 走看看