ZJOI2015 幻想乡战略游戏

题目描述:

luogu

bz

题解:

动态点分治。

记录点分树子树中到该点的所有价值。

为啥别人100行我150啊。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 100050;
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x = f*c;
}
int n,Q,hed[N],cnt;
struct EG
{
    int to,nxt;
    ll w;
}e[N<<1];
void ae(int f,int t,ll w)
{
    e[++cnt].to = t;
    e[cnt].nxt = hed[f];
    e[cnt].w = w;
    hed[f] = cnt;
}
int dep[N],siz[N],fa[N],son[N],top[N];
ll dis[N];
void dfs0(int u,int f)
{
    fa[u] = f,siz[u] = 1,dep[u] = dep[f]+1;
    for(int j=hed[u];j;j=e[j].nxt)
    {
        int to = e[j].to;
        if(to==f)continue;
        dis[to] = dis[u]+e[j].w;
        dfs0(to,u);
        siz[u]+=siz[to];
        if(siz[to]>siz[son[u]])son[u]=to;
    }
}
void dfs1(int u,int Top)
{
    top[u] = Top;
    if(son[u])dfs1(son[u],Top);
    for(int j=hed[u];j;j=e[j].nxt)
    {
        int to = e[j].to;
        if(to!=fa[u]&&to!=son[u])
            dfs1(to,to);
    }
}
int get_lca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        x = fa[top[x]];
    }
    return dep[x]<dep[y]?x:y;
}
ll get_dis(int x,int y){return dis[x]+dis[y]-2ll*dis[get_lca(x,y)];}
ll get_dis(int x,int y,int l){return dis[x]+dis[y]-2ll*dis[l];}
int sum,rt,sz[N],mx[N],ff[N];
ll k1[N],k2[N],k3[N];
bool mrk[N];
void get_rt(int u,int f)
{
    mx[u] = 0,sz[u] = 1;
    for(int j=hed[u];j;j=e[j].nxt)
    {
        int to = e[j].to;
        if(to==f||mrk[to])continue;
        get_rt(to,u);
        sz[u]+=sz[to];
        mx[u] = max(mx[u],sz[to]);
    }
    mx[u] = max(mx[u],sum-sz[u]);
    if(mx[u]<mx[rt])rt=u;
}
void work(int u)
{
    mrk[u] = 1;int tmp = sum;
    for(int j=hed[u];j;j=e[j].nxt)
    {
        int to = e[j].to;
        if(mrk[to])continue;
        rt=0,sum=(sz[to]>sz[u])?tmp-sz[u]:sz[to];
        get_rt(to,0);ff[rt]=u;work(rt);
    }
}
int Rt=1;
ll ans,ds[N][22];
void up(int x,ll y)
{
    for(int i=x,j=0,k=0;i;j=i,i=ff[i],k++)
    {
        ll now = y*ds[x][k];
        k1[i]+=now;k3[i]+=y;
        if(j)k2[j]+=now;
    }
}
ll query(int x)
{
    ll ret = 0;
    for(int i=x,j=0,k=0;i;j=i,i=ff[i],k++)
        ret+=k1[i]-k2[i]+(k3[i]-k3[j])*ds[x][k];
    return ret;
}
int turn()
{
    int son = 0;ll bas = query(Rt);
    for(int j=hed[Rt];j;j=e[j].nxt)
    {
        int to = e[j].to;ll tmp = query(to);
        if(tmp<bas)son=to,bas=tmp;
    }
    if(!son)return 0;
    Rt = son;return 1;
}
int main()
{
//    freopen("1.in","r",stdin);
    read(n),read(Q);
    for(int u,v,w,i=1;i<n;i++)
    {
        read(u),read(v),read(w);
        ae(u,v,w),ae(v,u,w);
    }
    dfs0(1,0),dfs1(1,1);
    mx[rt=0]=0x3f3f3f3f,sum=n;
    get_rt(1,0);work(rt);
    for(int i=1;i<=n;i++)
        for(int j=1,k=ff[i];k;j++,k=ff[k])
            ds[i][j]=get_dis(i,k);
    int x,y;
    read(x),read(y);
    Rt = x,ans = 0;up(x,y);
    puts("0");
    for(int i=2;i<=Q;i++)
    {
        read(x),read(y);
        up(x,y);
        while(turn());
        printf("%lld\n",query(Rt));
    }
    return 0;
}
View Code

 

posted @ 2019-07-08 18:05  LiGuanlin  阅读(...)  评论(...编辑  收藏