雅礼集训

[雅礼集训Day1]

真•神仙打架,考出来9分,暴力打炸?!总结一下第一题。
一道经典的支持换根的树链剖分,需要支持的操作有:
1.将根设为root.
2.设u, v的最近公共祖先为p, 将p的子树中的所有点的权值加上x.
3.查询u的子树中的所有点的权值和.
对于这一类题目,其实我们并不需要真正去换根,我们只需要记录一下当前的根是谁,然后在更改和查询的时候修改一下即可。
这道题真正的难点在于如何确定lca
题解:
经过一些简单的讨论可以知道,\(u\)\(v\)在以\(root\)为根时的\(lca\)为:\(lca(u, v)\),\(lca(u, root)\),\(lca(v, root)\)中原来深度最大的一个,其中\(lca(a, b)\)代表\(a\),\(b\)在以\(1\)为根时的\(lca\)
太菜了并不会证,所以记一下结论吧
确定了\(lca\)之后就好做了,对于查询操作,判断当前\(root\)是否在\(u\)的子树中,
如果不在,直接查询原来的子树
如果在,运用dfs序的连续性排除\(root\)所在儿子的子树,查询其他即可。画图模拟一下很好看出来。
注意特判\(u\)是否是\(root\)因为这个调了好久

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#define debug cout<<"....."<<endl;
#define lll long long
#define ll(x) (x*2)
#define rr(x) (x*2+1)
using namespace std;
lll read()
{
    lll x=0,w=1;char ch=getchar();
    while(ch>'9'||ch<'0') {if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*w;
}
lll n,q,cnt,m,opt,x,y,z,node;
lll head[300010],deep[300010],a[300010],size[300010],s[300010],pos[3000010];
lll sgm[1200010],lazy[1200010];
lll f[300010][21];
struct node{
    lll to,next;
}edge[600010];
void add(lll x,lll y)
{
    cnt++;edge[cnt].to=y;edge[cnt].next=head[x];head[x]=cnt;
}
void init()
{
    for(lll i=1;i<=20;i++)
        for(lll j=1;j<=n;j++)
            f[j][i]=f[f[j][i-1]][i-1];
}
void dfs(lll k,lll fa)
{
    lll v;
    s[++m]=k;pos[k]=m;
    for(lll i=head[k];i;i=edge[i].next)
    {
        v=edge[i].to;
        if(v==fa) continue;
        deep[v]=deep[k]+1;f[v][0]=k;
        dfs(v,k);
        size[k]+=size[v];
    }
    size[k]++;
}
lll LCA(lll x,lll y)
{
    if(deep[x]<deep[y]) swap(x,y);
    for(lll i=20;i>=0;i--)
        if(deep[f[x][i]]>=deep[y]) x=f[x][i];
    if(x==y) return x;
    for(lll i=20;i>=0;i--)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
void push_down(lll root,lll l,lll r)
{
    lll mid=(l+r)/2;
    if(!lazy[root]) return;
    sgm[ll(root)]+=(mid-l+1)*lazy[root];sgm[rr(root)]+=(r-mid)*lazy[root];
    lazy[ll(root)]+=lazy[root];lazy[rr(root)]+=lazy[root];lazy[root]=0;
    return;
}
void build(lll root,lll l,lll r)
{
    if(l>r) return;
    if(l==r)
    {
        sgm[root]=a[s[l]];
        return;
    }
    lll mid=(l+r)/2;
    if(l<=mid) build(ll(root),l,mid);
    if(r>mid) build(rr(root),mid+1,r);
    sgm[root]=sgm[ll(root)]+sgm[rr(root)];
}
void insert(lll root,lll l,lll r,lll left,lll right,lll v)
{
    if(l>r) return;
    if(l>right||r<left) return;
    if(left<=l&&r<=right)
    {
        sgm[root]+=(r-l+1)*v;lazy[root]+=v;
        return;
    }
    lll mid=(l+r)/2;
    push_down(root,l,r);
    if(l<=mid) insert(ll(root),l,mid,left,right,v);
    if(r>mid) insert(rr(root),mid+1,r,left,right,v);
    sgm[root]=sgm[ll(root)]+sgm[rr(root)];
}
lll query(lll root,lll l,lll r,lll left,lll right)
{
    if(l>r) return 0;
    if(l>right||r<left) return 0;
    if(left<=l&&r<=right) return sgm[root];
    lll mid=(l+r)/2;
    push_down(root,l,r);
    return query(ll(root),l,mid,left,right)+query(rr(root),mid+1,r,left,right);
}
int main()
{
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    n=read();q=read();node=1;
    for(lll i=1;i<=n;i++) a[i]=read();
    for(lll i=1;i<n;i++)
    {
        x=read();y=read();
        add(x,y);add(y,x);
    }
    deep[1]=1;
    dfs(1,0);
    build(1,1,n);
    init();
    for(lll i=1;i<=q;i++)
    {
        opt=read();
        if(opt==1)
            node=read();
        else if(opt==2)
        {
            x=read();y=read();z=read();
            lll lca,lca1=LCA(x,y),lca2=LCA(x,node),lca3=LCA(y,node);
            if(deep[lca1]>=deep[lca2]&&deep[lca1]>=deep[lca3]) lca=lca1;
            else if(deep[lca2]>=deep[lca1]&&deep[lca2]>=deep[lca3]) lca=lca2;
            else if(deep[lca3]>=deep[lca2]&&deep[lca3]>=deep[lca1]) lca=lca3;
            lll l=LCA(lca,node);
            if(lca==node) insert(1,1,n,1,n,z);
            else if(l==lca&&lca!=node)
            {
                l=node;
                for(lll i=20;i>=0;i--)
                    if(deep[f[l][i]]>deep[lca]) l=f[l][i];
                insert(1,1,n,1,n,z);insert(1,1,n,pos[l],pos[l]+size[l]-1,-z);
            }
            else insert(1,1,n,pos[lca],pos[lca]+size[lca]-1,z);
        }
        else if(opt==3)
        {
            x=read();
            lll l=LCA(x,node);
            if(x==node) printf("%lld\n",query(1,1,n,1,n));
            else if(l==x&&x!=node)
            {
                l=node;
                for(lll i=20;i>=0;i--)
                    if(deep[f[l][i]]>deep[x]) l=f[l][i];
                printf("%lld\n",query(1,1,n,1,pos[l]-1)+query(1,1,n,pos[l]+size[l],n));
            }
            else printf("%lld\n",query(1,1,n,pos[x],pos[x]+size[x]-1));
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lsgjcya/p/9218709.html
今日推荐