luoguP4751模板动态 DP(加强版)

Posted zyybot

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luoguP4751模板动态 DP(加强版)相关的知识,希望对你有一定的参考价值。

本人不会LCT。。只会全局平衡树

本题如何卡常?

其实也不用很夸张,稍微卡一卡即可

考虑最耗时的部分是Modify

先把Modify打成非递归版自不必说---①

然后考虑到(不管有没有封装结构体)用数组下表访问节点的话太慢了,然后全部改成指针~---②

接着看到维护区间信息的时候做矩阵乘法都是用max

封装的话会慢一些,所以改成宏(#define)---③

然后就是全部变量都开int(想不出开longlong的理由是什么。。。。)---④

变量的话能全局尽量全局(要是看不顺眼也可以不必)
能重复用就重复用,不要多次定义(特别是for里的变量,i,j,k什么的可以一次定义多次使用)---⑤

以上就是我自己打的优化了,这样就可以卡过

但是还可以更快

首先,快读的getchar()挺慢的
所以。。。

#define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;

数组访问很耗时,对于不可以改成指针的数组,我们可以这样搞:

//对于一个这样的数组:
int example[Span1][Span2]..[SpanN];
//以下是一个合法的随机访问方式,也是我们最常写的
example[a1][a2]..[an]
//可以改成:
example[(((a1-1)*SpanN+(a2-1))*Span(N-1)+(a3-1))*Span(N-2)....+an]
//然而这还不是最快的,它还可以变成:
*(example+(((a1-1)*SpanN+(a2-1))*Span(N-1)+(a3-1))*Span(N-2)....+an)

然后还有。。。超级毒瘤的,去掉大部分封装。
pushup 封装?删掉!矩阵乘法封装?删掉!

然后你就会得到一个飞快并且可读性为负的代码

嘛~其他的优化就超出我的能力范围了。想要更好的体验请参考wys的各种论文(其实我也不知道具体有什么QAQ

至于算法实现,这不是重点,本题解只讲解有关卡常的东西。。


#include<cstdio>
#define ls (k->son[0])
#define rs (k->son[1])
#define Matrix(a,b,c,d) ((Matrix){{a,b,c,d}})
int _ta,_tb;
#define max(a,b) ((_ta=a)>(_tb=b)?a:b)
const int MaxN=1000000,inf=0x3f3f3f3f;
inline void read(int &ans)
{
    ans=0;
    int sign=1;
    char c=getchar();
    while((c<'0'||c>'9')&&c!='-')
        c=getchar();
    if(c=='-')
        sign=-1,c=getchar();
    while(c>='0'&&c<='9')
        ans=ans*10+c-48,c=getchar();
    ans*=sign;
    return;
}
struct Matrix
{
    int s[2][2];
    friend inline Matrix operator * (const Matrix &a,const Matrix &b)
    {
        int i,j,k;
        Matrix c;
        for(i=0;i<2;++i)
            for(j=0;j<2;++j)
            {
                c.s[i][j]=-inf;
                for(k=0;k<2;++k)
                    c.s[i][j]=max(c.s[i][j],a.s[i][k]+b.s[k][j]);
            }
        return c;
    }
};
int n,m,val[MaxN+1];
int head[MaxN+1],to[MaxN*2],next[MaxN*2],tot=0;
inline void add(const int &x,const int &y)
{
    to[++tot]=y,next[tot]=head[x],head[x]=tot;
    return;
}
int dep[MaxN+1],size[MaxN+1],fth[MaxN+1],wson[MaxN+1],lsize[MaxN+1];
inline void dfs1(int x)
{
//  printf("dfs1 %d
",x);
    size[x]=1;
    for(int i=head[x];i;i=next[i])
        if(!size[to[i]])
        {
            dep[to[i]]=dep[x]+1,fth[to[i]]=x,dfs1(to[i]),size[x]+=size[to[i]];
            if(size[to[i]]>size[wson[x]])
                wson[x]=to[i];
        }
    lsize[x]=size[x]-size[wson[x]];
    return;
}
int f[MaxN+1][2],g[MaxN+1][2],v[MaxN+1];
inline void dfs2(int x)
{
    v[x]=1,f[x][0]=g[x][0]=0,f[x][1]=g[x][1]=val[x];
    if(wson[x])
    {
        dfs2(wson[x]);
        f[x][0]+=max(f[wson[x]][1],f[wson[x]][0]),f[x][1]+=f[wson[x]][0];
    }
    for(int i=head[x];i;i=next[i])
        if(!v[to[i]])
        {
            dfs2(to[i]);
            g[x][0]+=max(f[to[i]][1],f[to[i]][0]),g[x][1]+=f[to[i]][0];
            f[x][0]+=max(f[to[i]][1],f[to[i]][0]),f[x][1]+=f[to[i]][0];
        }
    return;
}
struct Node
{
    Node *son[2],*f;
    inline void pushup()
    {
        mtr2=mtr1;
        if(son[0])
            mtr2=son[0]->mtr2*mtr2;
        if(son[1])
            mtr2=mtr2*son[1]->mtr2;
        return;
    }
    inline int Max()
    {
        return max(mtr2.s[0][0],mtr2.s[1][0]);
    }
    Matrix mtr1,mtr2;
}node[MaxN+1];
Node *root;
inline void pushup(Node *k)
{
    k->mtr2=k->mtr1;
    if(ls)
        k->mtr2=ls->mtr2*k->mtr2;
    if(rs)
        k->mtr2=k->mtr2*rs->mtr2;
    return;
}
int stack[MaxN+1],top;
inline Node *Build2(int l,int r)
{
//  printf("Build2 %d %d
",l,r);
    if(l>r)
        return 0;
    int i,cur=0,tot=0;
    for(i=l;i<=r;++i)
        tot+=lsize[stack[i]];
    for(i=l,cur=lsize[stack[i]];i<=r;cur+=lsize[stack[++i]])
        if(cur*2>=tot)
        {
            node[stack[i]].son[0]=Build2(l,i-1);
            if(node[stack[i]].son[0])
                node[stack[i]].son[0]->f=node+stack[i];
            node[stack[i]].son[1]=Build2(i+1,r);
            if(node[stack[i]].son[1])
                node[stack[i]].son[1]->f=node+stack[i];
            (node+stack[i])->pushup();
//          printf("Matrix: %d %d %d %d
");
            return node+stack[i];
        }
    return 0;
}
inline void Modify(int x,int val)
{
    node[x].mtr1.s[1][0]+=val-::val[x];
    ::val[x]=val;
    for(Node *k=node+x;k;k=k->f)
        if(k->f&&k->f->son[0]!=k&&k->f->son[1]!=k)
        {
//          printf("1 %d
",x);
            k->f->mtr1.s[0][0]-=k->Max();
            k->f->mtr1.s[1][0]-=k->mtr2.s[0][0];
//          node[node[x].f].mtr1.s[0][1]=node[node[x].f].mtr1.s[0][0];
            k->pushup();
            k->f->mtr1.s[0][0]+=k->Max();
            k->f->mtr1.s[0][1]=k->f->mtr1.s[0][0];
            k->f->mtr1.s[1][0]+=k->mtr2.s[0][0];
        }
        else
            k->pushup();
    return;
}
inline Node *Build1(int top)
{
//  printf("build1 %d
",top);
    int i,x;
    for(x=top;x;x=wson[x])
        v[x]=1;
//  puts("1");
    for(x=top;x;x=wson[x])
        for(i=head[x];i;i=next[i])
            if(!v[to[i]])
                Build1(to[i])->f=node+x;
//  puts("2");
    ::top=0;
    for(x=top;x;x=wson[x])
        stack[++::top]=x;
    return Build2(1,::top);
}
#include<cstring>
int main()
{
    int i,a,b,lastans=0;
    read(n),read(m);
//  printf("%d %d
",n,m);
    for(i=1;i<=n;++i)
        read(val[i]);
    for(i=1;i<n;++i)
        read(a),read(b),add(a,b),add(b,a);
    dfs1(1),dfs2(1);
    memset(v,0,sizeof(v));
    for(i=1;i<=n;++i)
        node[i].mtr1=Matrix(g[i][0],g[i][0],g[i][1],-inf);
    root=Build1(1);
//  printf("%d
",Max(root));
    for(i=1;i<=m;++i)
    {
        read(a),read(b),a^=lastans;
//      printf("%d
",ans);
        Modify(a,b);
        printf("%d
",lastans=root->Max());
    }
    return 0;
}

以上是关于luoguP4751模板动态 DP(加强版)的主要内容,如果未能解决你的问题,请参考以下文章

luoguP6136 模板普通平衡树(数据加强版)

「LuoguP3796」 模板AC自动机(加强版)

[LuoguP4719][模板]动态DP(动态DP)

LuoguP4719 模板动态 DP(树形DP,矩阵加速,LCT)

[luoguP2045] 方格取数加强版(最小费用最大流)

LuoguP5024 保卫王国(动态DP,树形DP,矩阵加速,LCT)