【JZOJ 4388】染色

Description

【JZOJ 4388】染色_第1张图片

Solution

咋一眼看过去,那么像动态点分治…
大概想一下代码量,嗯…,不少…
那么来想一下树链剖分怎么打,
设一根节点的距离是c,与根的路径为s,
点x,y之间的距离也就是 cx+cy2CLCA(x,y)
那么我们只需要动态维护LCA即可,
在一条树链中,点x与所有与根的路径经过这条链的点的LCA和分两个部分:在x上面进入链;在x下面进入点;
对于前者,LCA就是它们第一次进入链时的点的s,用树状数组统计所有点的和,
对于后者,LCA就是x点,还是用树状数组统计个数,乘一下即可;
复杂度: O(nlog(n)2)

Code

#include<cstdio>
#include<cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
#define NX(q) ((q)&(-(q)))
using namespace std;
typedef long long LL;
const int N=100500;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int n,m,m1,zx0;
int B[2*N][3],A[N],B0=1;
LL f[N][2];
struct qqww
{int fa,lt,zx,si,ld,lt1;LL c1;}a[N];
LL ans;
bool z[N];
void join(int q,int w,int e)
{
    B[++B0][0]=A[q],A[q]=B0,B[B0][1]=w,B[B0][2]=e;
    B[++B0][0]=A[w],A[w]=B0,B[B0][1]=q,B[B0][2]=e;
}
int dfs1(int q,int fa,int c1)
{
    a[q].fa=fa;a[q].si=1;a[q].c1=c1;
    efo(i,q)if(B[i][1]!=fa)a[q].si+=dfs1(B[i][1],q,c1+B[i][2]);
    return a[q].si;
}
void dfs2(int q,int fa,int lt)
{
    if(!lt)lt=q;
    a[q].lt=lt;a[q].zx=++zx0;
    int mx=0;
    efo(i,q)if(fa!=B[i][1]&&a[B[i][1]].si>a[mx].si)mx=B[i][1];
    if(mx)dfs2(mx,q,lt);else a[lt].ld=q;
    efo(i,q)if(fa!=B[i][1]&&B[i][1]!=mx)dfs2(B[i][1],q,0);
}
LL find(int l,int r,int e)
{
    if(r<l)return 0;
    int q=r;LL ans=0;
    while(q)ans+=f[q][e],q-=NX(q);
    q=l-1;
    while(q)ans-=f[q][e],q-=NX(q);
    return ans;
}
void modify(int w)
{
    int q=a[w].zx;
    while(q<=n)f[q][1]+=a[w].c1,f[q][0]++,q+=NX(q);
}
LL find(int q)
{
    int w,e=0;
    LL ans=0;
    while(w=a[q].lt)
    {
        ans+=find(a[w].zx,a[q].zx,1)+find(a[q].zx+1,a[a[w].ld].zx,0)*a[q].c1-e*a[q].c1;
        e=a[w].lt1;q=a[w].fa;
    }
    return ans;
}
void change(int q)
{
    int w;
    while(w=a[q].lt)modify(q),a[w].lt1++,q=a[w].fa;
}
int main()
{
    int q,w,e;
    read(n),read(m1);
    fo(i,2,n)read(a[i].fa);
    fo(i,2,n)join(i,++a[i].fa,read(q));
    dfs1(1,0,0);
    dfs2(1,0,0);
    ans=0;
    while(m1--)
    {
        read(q),read(w);w++;
        if(q-1)printf("%lld\n",ans-2*find(w)+m*a[w].c1);
            else if(!z[w])change(w),z[w]=1,ans+=a[w].c1,m++;
    }
    return 0;
}

你可能感兴趣的:(树链剖分,动态树分治,动态点分治)