zoukankan      html  css  js  c++  java
  • 小清新数据结构题

    链接:https://www.luogu.org/problemnew/show/P3676

    题解:

    看暴力:每次修改只会影响到它到1的链,询问也是它到1的链

    那么考虑用树链剖分变成dfs序

    链剖都想了那就考虑用线段树维护这个dfs序上的信息

    维护dfs序上每个点子树的val和的平方和

    修改?

    假设修改uu的变化量为dd

    那么该完后uu的祖先们ii的子树平方和变成


    ji(sum[j]+d)2=(sum2[j]+2dsum[j]+d2)∑j∈i的子树(sum[j]+d)2=∑(sum2[j]+2∗d∗sum[j]+d2)

    设有子树大小为numnum,就是(sum2[j])+2dsum[j]+numd2∑(sum2[j])+2∗d∑sum[j]+num∗d2

    那么我们只需要再维护每个点子树的val和的和就可以+lazy修改了

    每个点子树的val和的和也很好弄直接区间加lazy就好

    查询?

    根据暴力推一下,ssffss,ff又减又加的,最后会消除一些

    设根为1的答案为ans1ans1,当前询问的点到根的路径上有xx个点,分别标成u1uxu11uxu1到ux,u1就是1,ux就是当前点,sum[i]i

    valsum[i]表示i子树的val和

    那么ans=ans1xi=1sum2[ui]+xi=2(sum[u1]sum[ui])ans=ans1−∑i=1xsum2[ui]+∑i=2x(sum[u1]−sum[ui])(很好推的)

    化简一下

    ans=ans1sum2[u1](x1)2sum[u1]xi=2sum[ui]ans=ans1−sum2[u1]∗(x−1)−2∗sum[u1]∑i=2xsum[ui]

    sumsum和线段树+链剖查询就好了

    sum[u1]sum[1]sum[u1]即sum[1]就是整个数的val和可以单点查询也可维护全局变量

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 210000
    struct{
        int a,b;
    }a[maxn*2];
    struct{
        int h,t,x1,x2,lazy;
    }p[maxn*4];
    int num,m,n,l;
    int v[maxn],size[maxn],real2[maxn],
    top[maxn],id[maxn],head[maxn],dep[maxn],
    fa[maxn],son[maxn],x1[maxn],x2[maxn];
    void arr(int x,int y)
    {
        a[++l].a=head[x];
        a[l].b=y;
        head[x]=l;
    }
    void dfs1(int x,int y)
    {
        fa[x]=y; dep[x]=dep[y]+1;
        son[x]=-1; size[x]=1;
        int u=head[x];
        while (u)
        {
            int v=a[u].b;
            if (v!=y)
            {
                dfs1(v,x);
                size[x]+=size[v];
                if (son[x]!=-1||
                size[son[x]]<size[v])
                son[x]=v;
            }
            u=a[u].a;
        }
    }
    void dfs2(int x,int y)
    {
        top[x]=y; num++;
        id[x]=num; real2[num]=x;
        if (son[x]==-1) return;
        dfs2(son[x],y);
        int u=head[x];
        while (u)
        {
            int v=a[u].b;
            if (v!=fa[x]&&v!=son[x])
              dfs2(v,v);
            u=a[u].a;
        }
    }
    void dfs3(int x)
    {
        int u=head[x];
        x1[id[x]]=v[x];
        while (u)
        {
            int v=a[u].b;
            if (v!=fa[x])
            { 
              dfs3(v);
              x1[id[x]]+=x1[id[v]];
            }
            u=a[u].a;
        }
        x2[id[x]]=pow(x1[id[x]],2);
    }
    #define mid (p[x].h+p[x].t)/2
    void updata(int x)
    {
        p[x].x1=p[x*2].x1+p[x*2+1].x1;
        p[x].x2=p[x*2].x2+p[x*2+1].x2;
    }
    void build(int x,int h,int t)
    {
        p[x].h=h; p[x].t=t;
        if (h==t)
        {
            p[x].x1=x1[h];
            p[x].x2=x2[h];
            return;
        }
        build(x*2,h,mid); build(x*2+1,mid+1,t);
        updata(x); 
    }
    void down(int x)
    {
        if (!p[x].lazy) return;
        if (p[x].h!=p[x].t)
        {
            p[x*2].lazy+=p[x].lazy;
            p[x*2+1].lazy+=p[x].lazy;
        }
        p[x].x2+=p[x].x1*2*p[x].lazy+
        (p[x].t-p[x].h+1)*p[x].lazy*p[x].lazy;
        p[x].x1+=p[x].lazy*(p[x].t-p[x].h+1);
        p[x].lazy=0;
    }
    void change2(int x,int h,int t,int sum)
    {
        down(x);
        if (p[x].t<h||p[x].h>t) return;
        if (h<=p[x].h&&p[x].t<=t)
        {
            p[x].lazy=sum; down(x);
            return;
        }
        change2(x*2,h,t,sum);
        change2(x*2+1,h,t,sum);
        updata(x);
    }
    int query1(int x,int h,int t)
    {
        down(x);
        if (p[x].t<h||p[x].h>t) return(0);
        if (h<=p[x].h&&p[x].t<=t)
        {
            return(p[x].x1); 
        } 
        return(query1(x*2,h,t)+query1(x*2+1,h,t));
    }
    int query2(int x,int h,int t)
    {
        down(x);
        if (p[x].t<h||p[x].h>t) return(0);
        if (h<=p[x].h&&p[x].t<=t)
        {
            return(p[x].x2); 
        } 
        return(query2(x*2,h,t)+query2(x*2+1,h,t));
    }
    void change(int x,int y)
    {
        int f1=top[x];
        while (true)
        {
            change2(1,id[f1],id[x],y);
            if (f1==1) return;
            x=fa[f1]; f1=top[x];
        }
    }
    int query(int x)
    {
        int f1=top[x],tmp=0;
        while (true)
        {
            tmp+=query1(1,id[f1],id[x]);
            if (f1==1) return(tmp);
            x=fa[f1]; f1=top[x];
        }
    }
    int main()
    {
        std::ios::sync_with_stdio(false);
        cin>>n>>m;
        int c,d,e;
        for (int i=1;i<=n-1;i++)
        {
            cin>>c>>d;
            arr(c,d); arr(d,c);
        }
        for (int i=1;i<=n;i++)
          cin>>v[i];
        dfs1(1,0); dfs2(1,1); dfs3(1);
        build(1,1,n);
        for (int i=1;i<=m;i++)
        {
            cin>>c;
            if (c==1)
            {
                cin>>d>>e;
                change(d,e-v[d]);
                v[d]=e;
            }
            if (c==2)
            {
                cin>>d;
                int x=query1(1,1,1),
                    y=query2(1,1,n),
                    z=query(d)-x;
                cout<<y+x*x*(dep[d]-1)-2*x*z<<endl;
            }
        }
        return 0;
    } 
    View Code

     这题的难点主要在于换根操作

    分析出上面的式子后就简单了

  • 相关阅读:
    java jdk 安装后目录下没有 jre
    解决leader-line生成的svg线不能被html2canvas转成图片问题
    css 计数实现目录索引
    前端架构入门
    js 尺寸信息
    阿里云25端口被封,换465端口发送
    appache官网下载 httpClient
    oc基础:类的定义
    指针的地址(地址的地址)
    0 ‘与‘’、 ‘0’
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/8452313.html
Copyright © 2011-2022 走看看