51nod-1462: 樹據結構

【傳送門:51nod-1462


簡要題意:

  給出一棵n個點的樹,每一個點有兩個權值v,t
html

  有Q個操做,有兩種操做:node

  1.將x到根上的路徑上的點的v值都加上dspa

  2.將x到根上的路徑上的點的t值都加上每一個點的v值*dcode

  最後求出全部點的t值htm


題解:

  顯然能夠直接樹鏈剖分作,不過lazy標記下放真麻煩,由於操做有互相影響
blog

  發現一種神標記方法——用矩陣ci

  對於一個點,它的信息表示爲$$ \begin{matrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ v & t & 1 \\ \end{matrix} $$get

  而對於第一種操做,就將點的信息乘上$$ \begin{matrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ d & 0 & 1 \\ \end{matrix} $$string

  而第二種操做則乘上$$ \begin{matrix} 1 & d & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \\ \end{matrix} $$it

  這樣就不用擔憂互相影響了,由於矩陣乘法知足結合律,因此直接將操做按順序乘起來就好了

  據說能夠離線CDQ作


參考代碼:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
struct trnode
{
    int l,r,lc,rc;
}tr[210000];int trlen;
struct Matrix
{
    LL a[4][4];
    Matrix()
    {
        memset(a,0,sizeof(a));
    }
}D[210000],cmp;
Matrix multi(Matrix a,Matrix b)
{
    Matrix c;
    for(int i=1;i<=3;i++)
    {
        for(int j=1;j<=3;j++)
        {
            for(int k=1;k<=3;k++)
            {
                c.a[i][j]+=a.a[i][k]*b.a[k][j];
            }
        }
    }
    return c;
}
void bt(int l,int r)
{
    trlen++;int now=trlen;
    tr[now].l=l;tr[now].r=r;
    D[now].a[1][1]=D[now].a[2][2]=D[now].a[3][3]=1;
    tr[now].lc=tr[now].rc=-1;
    if(l<r)
    {
        int mid=(tr[now].l+tr[now].r)/2;
        tr[now].lc=trlen+1;bt(l,mid);
        tr[now].rc=trlen+1,bt(mid+1,r);
    }
}
struct node
{
    int x,y,next;
}a[110000];int len,last[110000];
void ins(int x,int y){a[++len]=(node){x,y,last[x]};last[x]=len;}
int son[110000],tot[110000];
void dfs1(int x)
{
    tot[x]=1;son[x]=0;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        dfs1(y);
        if(tot[y]>tot[son[x]]) son[x]=y;
        tot[x]+=tot[y];
    }
}
int top[110000],ys[110000],z;
void dfs2(int x,int tp)
{
    ys[x]=++z;top[x]=tp;
    if(son[x]!=0) dfs2(son[x],tp);
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=son[x]) dfs2(y,y);
    }
}
void update(int now)
{
    int lc=tr[now].lc,rc=tr[now].rc;
    if(lc!=-1) D[lc]=multi(D[lc],D[now]);
    if(rc!=-1) D[rc]=multi(D[rc],D[now]);
    memset(D[now].a,0,sizeof(D[now].a));
    D[now].a[1][1]=D[now].a[2][2]=D[now].a[3][3]=1;
}
void change(int now,int l,int r)
{
    if(tr[now].l==l&&tr[now].r==r)
    {
        D[now]=multi(D[now],cmp);
        return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    update(now);
    if(r<=mid) change(lc,l,r);
    else if(l>mid) change(rc,l,r);
    else change(lc,l,mid),change(rc,mid+1,r);
}
int fa[110000];
void solve(int x)
{
    int tx=top[x];
    while(x!=0)
    {
        change(1,ys[tx],ys[x]);
        x=fa[tx];tx=top[x];
    }
}
LL d[110000];
void out(int now)
{
    if(tr[now].l==tr[now].r)
    {
        d[tr[now].l]=D[now].a[3][2];
        return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc;
    update(now);
    if(lc!=-1) out(lc);
    if(rc!=-1) out(rc);
}
int main()
{
    int n;
    scanf("%d",&n);
    len=0;memset(last,0,sizeof(last));
    for(int i=2;i<=n;i++)
    {
        scanf("%d",&fa[i]);
        ins(fa[i],i);
    }
    dfs1(1);
    z=0;dfs2(1,1);
    trlen=0;bt(1,z);
    cmp.a[1][1]=cmp.a[2][2]=cmp.a[3][3]=1;
    int Q;
    scanf("%d",&Q);
    while(Q--)
    {
        int t,x;LL d;
        scanf("%d%d%lld",&t,&x,&d);
        if(t==1) cmp.a[1][2]=0,cmp.a[3][1]=d,solve(x);
        else cmp.a[3][1]=0,cmp.a[1][2]=d,solve(x);
    }
    out(1);
    for(int i=1;i<=n;i++) printf("%lld\n",d[ys[i]]);
    return 0;
}
相關文章
相關標籤/搜索