3924: [Zjoi2015]幻想乡战略游戏(点分树)

题目

链接

分析

点分树裸题!!!

其实是不想写题解

大概就是要新建立点分树,基本上是一个新树了。要维护以每个结点为根的子树信息来辅助查询。

查询的时候就是找子树中比当前结点优的点然后。这里跳到那个结点的根结点去。

还有就是会被菊花卡成O(n)的查询,但是这题有限制子树不超过20个。

代码

#include//注意距离都要开LL 
using namespace std;
typedef long long LL;
const int maxn=1e5+105,oo=16;
int np,first[maxn];
struct edge{
    int to,next,w;
}E[maxn<<1];
void add(int u,int v,int w)
{
    E[++np]=(edge){v,first[u],w};
    first[u]=np;
}
int n,m,rt,root;
int dep[maxn],fa[maxn][oo+5],sz[maxn],dist[maxn];
void DFS(int i,int f,int d,int dis)
{
    dep[i]=d,dist[i]=dis;
    fa[i][0]=f;
    for(int j=1;j<=oo;j++)
        fa[i][j]=fa[fa[i][j-1]][j-1];
    for(int p=first[i];p;p=E[p].next)
    {
        int j=E[p].to;
        if(j==f)continue;
        DFS(j,i,d+1,dis+E[p].w);
    }
}
int LCA(int u,int v)
{
    if(dep[u]int delt=dep[u]-dep[v];
    for(int j=oo;j>=0;j--)
        if(delt&(1<if(u==v)return u;
    for(int j=oo;j>=0;j--)
        if(fa[u][j]!=fa[v][j])u=fa[u][j],v=fa[v][j];
    return fa[u][0];
}
int getDist(int u,int v)
{
    return dist[u]+dist[v]-2*dist[LCA(u,v)];
}
int pa[maxn],sum[maxn];
LL cost[maxn],pacost[maxn];
bool vis[maxn];
int np2,first2[maxn];
struct edge2{
    int to,next,rt;
}E2[maxn];
void add2(int u,int v,int rt)
{
    E2[++np2]=(edge2){v,first2[u],rt};
    first2[u]=np2;
}
void getRoot(int i,int f,int tot)
{
    sz[i]=1;
    int mx=0;
    for(int p=first[i];p;p=E[p].next)
    {
        int j=E[p].to;
        if(j==f || vis[j])continue;
        getRoot(j,i,tot);
        mx=max(mx,sz[j]);
        sz[i]+=sz[j];
    }
    mx=max(mx,tot-sz[i]);
    if(mx<=tot/2)root=i;
}
void Build(int i,int f,int tot)
{
    pa[i]=f;vis[i]=1;
    for(int p=first[i];p;p=E[p].next)
    {
        int j=E[p].to;
        if(vis[j])continue;
        getRoot(j,0,sz[j]void modify(int u,int e)
{
    int dist;
    sum[u]+=e;
    for(int i=u;pa[i];i=pa[i])
    {
        dist=getDist(u,pa[i]);
        sum[pa[i]]+=e;
        cost[pa[i]]+=1ll*dist*e;
        pacost[i]+=1ll*dist*e;
    }
}
LL calc(int u)
{
    int dist;
    LL ret=cost[u];
    for(int i=u;pa[i];i=pa[i])
    {
        dist=getDist(u,pa[i]);
        ret+=cost[pa[i]]-pacost[i];
        ret+=1ll*(sum[pa[i]]-sum[i])*dist;
    }
    return ret;
}
LL query(int i)
{
    LL tmp=calc(i);
    for(int p=first2[i];p;p=E2[p].next)
    {
        int j=E2[p].to;
        if(calc(j)return query(E2[p].rt);
    }
    return tmp;
}
void Init()
{
    int u,v,w;
    scanf("%d%d",&n,&m);
    for(int i=1;iscanf("%d%d%d",&u,&v,&w);
        add(u,v,w);add(v,u,w);
    }

    DFS(1,0,1,0);//因为我们是求个距离,所以随便哪个是根都可以 

    getRoot(1,0,n);
    rt=root;
    Build(rt,0,n);
}
int main()
{
    //freopen("in.txt","r",stdin);
    Init();
    int u,e;
    while(m--)
    {
        scanf("%d%d",&u,&e);
        modify(u,e);
        printf("%lld\n",query(rt));
    }
    return 0;
}

你可能感兴趣的:(BZOJ,点分治)