【luoguP3676】 小清新数据结构题 推式子(LCT维护)

挺有趣的一个数据结构题,不必用 LCT 维护,只不过 LCT 比较好写 ~

code:

#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#define N 200008
#define ll long long
#define lson s[x].ch[0]
#define rson s[x].ch[1]
using namespace std;
ll ans;
void setIO(string s)
{
    freopen((s+".in").c_str(),"r",stdin);
    // freopen((s+".out").c_str(),"w",stdout);
}
int edges;
int sta[N],hd[N],to[N<<1],nex[N<<1],val[N];
void Add(int u,int v) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; }
struct LCT
{
    int ch[2],rev,f,size;
    ll tag,sum,v;
}s[N];
int get(int x) { return s[s[x].f].ch[1]==x; }
int Isr(int x) { return s[s[x].f].ch[0]!=x&&s[s[x].f].ch[1]!=x;}
void pushup(int x)
{
    s[x].sum=s[lson].sum+s[rson].sum+s[x].v;
    s[x].size=s[lson].size+s[rson].size+1;
}
void add(int x,ll v)
{
    s[x].v+=v;
    s[x].sum+=v*1ll*s[x].size;
    s[x].tag+=v;
}
void rotate(int x)
{
    int old=s[x].f,fold=s[old].f,which=get(x);
    if(!Isr(old)) s[fold].ch[s[fold].ch[1]==old]=x;
    s[old].ch[which]=s[x].ch[which^1];
    if(s[old].ch[which]) s[s[old].ch[which]].f=old;
    s[x].ch[which^1]=old,s[old].f=x,s[x].f=fold;
    pushup(old),pushup(x);
}
void pushdown(int x)
{
    if(s[x].tag)
    {
        if(lson) add(lson,s[x].tag);
        if(rson) add(rson,s[x].tag);
        s[x].tag=0;
    }
}
void splay(int x)
{
    int u=x,v=0,fa;
    for(sta[++v]=u;!Isr(u);u=s[u].f) sta[++v]=s[u].f;
    for(;v;--v) pushdown(sta[v]);
    for(u=s[u].f;(fa=s[x].f)!=u;rotate(x))
        if(s[fa].f!=u)
            rotate(get(fa)==get(x)?fa:x);
}
void Access(int x)
{
    for(int y=0;x;y=x,x=s[x].f)
        splay(x),rson=y,pushup(x);
}
void dfs(int u,int ff)
{
    s[u].f=ff;
    s[u].v=val[u];
    for(int i=hd[u];i;i=nex[i])
        if(to[i]!=ff) dfs(to[i],u),s[u].v+=s[to[i]].v;
    ans+=s[u].v*s[u].v;
    pushup(u);
}
int main()
{
    // setIO("input");
    ll tot=0ll;
    int i,j,n,Q,x,y;
    scanf("%d%d",&n,&Q);
    for(i=1;i<n;++i)  scanf("%d%d",&x,&y),Add(x,y),Add(y,x);
    for(i=1;i<=n;++i) scanf("%d",&val[i]),tot+=val[i];
    dfs(1,0);
    for(i=1;i<=Q;++i)
    {
        int op;
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%d",&x,&y);
            int d=y-val[x];
            Access(x),splay(x);
            ans+=2ll*s[x].sum*d+1ll*s[x].size*d*d;
            add(x,d);
            tot+=d;
            val[x]=y;        

        }
        else
        {
            scanf("%d",&x);
            Access(x),splay(x);
            int siz=s[x].size-1;
            ll sum=s[x].sum-tot;
            printf("%lld\n",ans+1ll*siz*tot*tot-2ll*tot*sum);
        }
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/guangheli/p/12122978.html

时间: 2024-10-12 08:25:53

【luoguP3676】 小清新数据结构题 推式子(LCT维护)的相关文章

[Luogu3676]小清新数据结构题

题面戳我 题意:给一棵树,树上有点权,每次操作为修改一个点的点权,或者是询问以某个点为根时,每棵子树(以每个点为根,就有n棵子树)点权和的平方和. \(n\le2*10^5\),保证答案在long long范围内 sol 我们设\(s_i\)表示以\(p\)为整棵树的根时,以\(i\)为根的子树的点权和.设\(Sum\)表示所有点的点权和,即\(Sum=\sum_{i=1}^{n}val_i\). 所以这道题给出\(p\),就是要你求\(\sum_{i=1}^{n}s_i^2\). 我们先看\(

【刷题】洛谷 P3676 小清新数据结构题

题目背景 本题时限2s,内存限制256M 题目描述 在很久很久以前,有一棵n个点的树,每个点有一个点权. 现在有q次操作,每次操作是修改一个点的点权或指定一个点,询问以这个点为根时每棵子树点权和的平方和. (题目不是很好懂,没看太懂的可以看看样例解释) 输入输出格式 输入格式: 第一行两个整数n.q. 接下来n-1行每行两个整数a和b,表示树中a与b之间有一条边,保证给出的边不会重复. 接下来一行n个整数,第i个整数表示第i个点的点权. 接下来q行每行两或三个数,如果第一个数为1,那么接下来有两

Luogu3676 小清新数据结构题 动态点分治

传送门 换根类型的统计问题动态点分治都是很好做的. 设所有点的点权和为$sum$ 首先,我们先不考虑求$\sum\limits_i s_i^2$,先考虑如何在换根的情况下求$\sum\limits_i s_i$. 考虑一个点$i$会被统计多少次,显然是$dep_i+1$,那么$\sum\limits_i s_i = \sum\limits_i (dep_i+1) \times val_i = \sum\limits_i dep_i \times val_i + sum$. $\sum\limit

Luogu 3676 小清新数据结构题

推荐博客: http://www.cnblogs.com/Mychael/p/9257242.html 感觉还挺好玩的 首先考虑以1为根,把每一个点子树的权值和都算出来,记为$val_{i}$,那么在所有操作都没有开始的时候(以$1$为根的)$ans_{1} = \sum_{i= 1}^{n}val_{i}^{2}$ 考虑到一个修改的操作只会对修改的点$x$到根($1$)链上的点产生影响,那么一次修改只要修对这条树链上的点增加$v - a_{x}$(假设修改后的值为$v$)就好了. 链剖之后线段

lp3676 小清新数据结构题

传送门 Description 有一棵\(n\)个点的树,每个点有一个点权. 现在有\(q\)次操作,每次操作是修改一个点的点权或指定一个点,询问以这个点为根时每棵子树点权和的平方和. Solution 我们设\(Sum=\sum_{i=1}^{n} w_i\),\(s_i\)表示\(i\)子树的权值和 发现不管根是哪个节点,\(W=\sum_{i=1}^n s_i(Sum-s_i)\)都是一个定值 因为它相当于对于每条边连接的两个联通块的"点权和的积"的和 所以,我们要求的\(\su

小清新签到题(DP)

传送门 然鹅我并不觉得这道题很清新rua 思维巧妙!(参考) 对于第k小,我们可以这样考虑,若是第k小,那么比它小的方案应该是有k-1个. 在排列组合中,若固定i放在j位置,方案数是确定的,即:i固定在j位置,满足这个条件的序列的rank是在一个范围内的. 对于逆序对 常见思考方式是从小到大枚举数字,考虑对逆序对个数做出的贡献(从小到大插入,后插入不会对前插入造成影响) 设f[i][j]为i个数,j个逆序对的方案数,可得转移方程为 f[i][j]=f[i-1][j]+f[i-1][j-1]+……

【LCT维护子树信息】uoj207 共价大爷游长沙

这道题思路方面就不多讲了,主要是通过这题学一下lct维护子树信息. lct某节点u的子树信息由其重链的一棵splay上信息和若干轻儿子子树信息合并而成. splay是有子树结构的,可以在rotate,access的时候由儿子update到父亲,而轻儿子的信息update不上来,需要另外记一下. 记sum[x]为我们要求的子树信息,xu[x]为x的轻儿子的子树信息. (即,xu[x]由轻儿子的sum更新,sum[x]由xu[x]和splay子树上的儿子的sum更新. 这样我们就可以完整地用lct维

推式子小技巧

推式子小技巧 标签(空格分隔): 数学 先讲一些万金油 交换求和顺序,这个很\(naive\). 式子可以随意提到与其无关的枚举项前后,这个也很\(naive\). 算贡献思想,这个非常重要,一般需要一点个人能力,只要转化前后每一项被算的次数一样就可以 熟记常见结论,对模数敏感一点,该卷积的就卷起来用多项式,该反演的反演,该容斥的容斥. 还要一些灵感啊\(QAQ\) 卷积 这个我玩的不怎么熟,只会常见形式. \[\sum\limits_{i=1}^{n}f(i)g(n-i)\] 没错你碰见什么式

HZOJ 20190727 T2 单(树上dp+乱搞?+乱推式子?+dfs?)

考试T2,考试时想到了40pts解法,即对于求b数组,随便瞎搞一下就oxxk,求a的话,很明显的高斯消元,但考试时不会打+没开double挂成10pts(我真sb),感觉考试策略还是不够成熟,而且感觉考试时间很不够用,一直在瞎yy+code,听讲题DeepinC 12min就打出了T150pts,这不仅是思维上的劣势,而且打代码的速度必须要加上来啊,不然就算有好想法也打不出来(也没啥好想法). 接下来就是正经八本的题解了: 首先我们可以来一波玄学复杂度分析,数据范围1e5,要么$O(nlogn)