洛谷 小清新数据结构题

前言

标算点分治,蒟蒻树链剖分。

题面

原题可以戳。由于表达能力过弱,所以自己不再复述题面。

sol

可能有一大堆 Σ Σ 。。
然而我并不会那么数学的符号。。。
所以全凭脑算。
在不考虑换根与修改的情况下,只要理解了题意,求解就是dfs。但由于发现修改是一个点一个点修改的,所以每次要针对一个点的修改来算出与修改前的贡献差。所以说要针对出一个点来算贡献。如果我们是按一个一个点来算贡献的话,就可以通过枚举他所在的子树来算贡献。发现了一个平方,手推式子不可避免。
如果一个点改变了,考虑他所在的一个子树,把平方式子拆开,就形如 a2+b2+c2+...+2ab+2bc+2ac+... a 2 + b 2 + c 2 + . . . + 2 a b + 2 b c + 2 a c + . . . 显然有的与a(假设a发生变化)无关的式子,这些式子的值肯定不变.除了一个平方项,其他都可以提一个 2a 2 a 出来,剩下的就是一个求和。这样针对每一个点,在以1为根的情况下,维护他的子树的权值和(包括自己)。这样,用线段树(或者树状数组),求出每一个包括a的子树的权值和减去几个a再乘一个 2a 2 a .
如果根变了,那么,先设现在的根为 u u ,设 a1,a2... a 1 , a 2 . . . 为在以1为根的情况下,子树i的权值和为 ai a i b1,b2... b 1 , b 2 . . . 是以 u u 为根的情况。以1为根的答案为 ans a n s ,u为根的情况答案为 Ans A n s ,然后推一波式子,主要是要把 bi b i 消掉,因为没有维护 bi b i .

code

#include
#define LL long long
using namespace std;
namespace zjy_io{
    inline char gc(){
        static char buf[1<<6],*p1=buf,*p2=buf;
        return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<6,stdin),p1==p2)?EOF:*p1++;
    }
    template <class T>
    inline void read(T&data){
        data=0;register int caa=1;register char ch=0;
        while((ch!='-')&&(ch<'0'||ch>'9'))ch=gc();
        ch=='-'?caa=-1,ch=gc():caa=1;
        while(ch<='9'&&ch>='0'){
            data=(data<<3)+(data<<1)+(ch^48);
            ch=gc();
        }
        data=data*caa;
    }
}
using namespace zjy_io;
const int _ = 2e5+1e2;
struct edge{
    int to,nt;
}e[_<<1];
int s[_],head[_],n,q,deep[_],top[_],son[_],size[_],fa[_],dfn[_],fdfn[_],cnt;
LL sum[_],tree[_<<2],lazy[_<<2];
LL ans1,ALL;
inline void update(register int qp){
    tree[qp]=tree[qp<<1]+tree[qp<<1|1];return;
}
inline void pushdown(register int qp,register int le,register int ri){
    if(lazy[qp]){
        register int mid= (le+ri)>>1,len1=mid+1-le,len2=ri-mid;
        lazy[qp<<1]+=lazy[qp],tree[qp<<1]+=lazy[qp]*len1;
        lazy[qp<<1|1]+=lazy[qp],tree[qp<<1|1]+=lazy[qp]*len2;
        lazy[qp]=0; 
    }
    return;
}
void modify(const int l,const int r,register LL zh,int L,int R,register int qp){
    if(L>=l&&R<=r){tree[qp]+=zh*(R-L+1);lazy[qp]+=zh;return;}
    register int mid=(L+R)>>1;
    if(l<=mid)modify(l,r,zh,L,mid,qp<<1);
    if(r>mid)modify(l,r,zh,mid+1,R,qp<<1|1);
    update(qp);return;
}
LL Query(const int l,const int r,register int L,register int R,int qp){
    if(L>=l&&R<=r){
        return tree[qp];
    }
    pushdown(qp,L,R);
    register int mid= (L+R)>>1;
    register LL kkk=0;
    if(l<=mid)kkk+=Query(l,r,L,mid,qp<<1);
    if(r>mid)return kkk+Query(l,r,mid+1,R,qp<<1|1);
    return kkk;
}
inline LL pre_query(register int a){
    if(a==1)return ans1;
//int gnt=0;
    register LL delta=0;
    register int Begin=a,End;
    while(Begin){
        /*if(a==3){++gnt;if(gnt>5)exit(0);
        cout<
        End=top[Begin];
        delta=delta+2LL*Query(dfn[End],dfn[Begin],1,n,1)*ALL;
        Begin=fa[End];
    }
    delta=1LL*(deep[a]-deep[1]+2)*(ALL)*(ALL)-delta;
    return ans1+delta;
}
void add(register int a,register int b){e[++cnt].to=a,e[cnt].nt=head[b],head[b]=cnt;}
inline void pre_fix(register int a,register int b){
    register LL delta=0;
    register int Pre=s[a],Now=b;s[a]=b;ALL=ALL+Now-Pre;
    delta=delta+1LL*deep[a]*(1LL*Now*Now-1LL*Pre*Pre);
    register int Begin=a;
    while(Begin){

        register int End=top[Begin];
        register LL dist = ( Query(dfn[End],dfn[Begin],1,n,1) - (deep[Begin]-deep[End]+1)*Pre)*(Now-Pre)*2;
        delta=delta+dist;
        modify(dfn[End],dfn[Begin],Now-Pre,1,n,1);
        Begin=fa[End];
    }
    ans1+=delta;
}
void dfsI(register int now,register int ff){
    fa[now]=ff,deep[now]=deep[ff]+1,sum[now]=s[now];
    size[now]=1;register int mx=0;
    for(register int i=head[now];i;i=e[i].nt){
        if(e[i].to==ff)continue;
        dfsI(e[i].to,now);
        size[now]+=size[e[i].to];
        if(mxreturn;
}
void dfsII(register int now,register int topf){
    dfn[now]=++cnt,fdfn[cnt]=now;
    top[now]=topf;
    modify(cnt,cnt,sum[now],1,n,1);
    if(son[now])
        dfsII(son[now],topf);
    for(register int i=head[now];i;i=e[i].nt){
        if(e[i].to==fa[now]||e[i].to==son[now])continue;
        dfsII(e[i].to,e[i].to);
    }
    return;
}
int main(){
    read(n);read(q);
    for(register int i=1,a,b;ifor(register int i=1;i<=n;++i)read(s[i]),ALL+=s[i];
    dfsI(1,0);cnt=0;
    dfsII(1,1);
    while(q--){
        register int ki,a,b;
        read(ki);
        if(ki==1){
            read(a),read(b);
            pre_fix(a,b);
        }
        else {
            read(a);
            printf("%lld\n",pre_query(a));
        }
    }
}

你可能感兴趣的:(题解,线段树,树链剖分,题解,树链剖分)