zoukankan      html  css  js  c++  java
  • [JZOJ 5908] [NOIP2018模拟10.16] 开荒(kaihuang)解题报告 (树状数组+思维)

    题目链接:

    https://jzoj.net/senior/#contest/show/2529/1

    题目:

    题目背景:
    尊者神高达作为一个萌新,在升级路上死亡无数次后被一只大黄叽带回了师门。他加入师门后发现有无穷无尽的师兄弟姐妹,这几天新副本开了,尊者神高达的师门作为一个 pve师门,于是他们决定组织一起去开荒。

    题目描述:
    师门可以看做以 1 为根的一棵树,师门中的每一个人都有一定的装备分数。一共会有 q 个事件。每个事件可能是一次开荒,也可能是因为开荒出了好装备而导致一个人的装分出现了变化。对于一次开荒,会有 k 个人组织,由于师门的号召力很强,所以所有在组织者中任意两个人简单路径上的人都会参加。

    题目大意:

    在树上给出多个点,每次询问包含这些点的最小连通块的点权之和,带修改

    题解:

    对于每一个询问,我们把点按照dfs序从小到大排序。画个图我们发现,假设当前点为第i个点,第i个点的贡献就是从第i个点到与第i-1个点的LCA上的路径上的点权和,但是不包括LCA的点权。为什么不包括LCA的点权呢?发现其实我们从第1个点到最终的LCA上的点权和(这个要算上最终的LCA)都没有计算,最后一起计算就是了

    为什么是对的呢?我们考虑到排名靠后的点要么在上一个点的子树里,要么就是新开一个子树。对于前者我们发现公共LCA不上移,直接计算到上一个点的路径和就是了,而事实上上一个点和这个点的LCA就是上一个点。对于后者我们发现公共LCA发生上移,这在最终的答案被我们统计了进去。

    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cstdio>
    #include<vector>
    using namespace std;
    typedef long long ll;
    
    const int N=1e5+15;
    int n,Q,tot,tim;
    int head[N],son[N],dep[N],fa[N][25],dfn[N],id[N],sz[N],a[N];
    ll val[N],t[N];
    struct EDGE
    {
        int to,nxt;
    }edge[N<<1];
    inline ll read()
    {
        char ch=getchar();
        ll s=0,f=1;
        while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
        return s*f;
    }
    void link(int u,int v)
    {
        edge[++tot]=(EDGE){v,head[u]};
        head[u]=tot;
    }
    void dfs(int x,int pre)
    {
        sz[x]=1;fa[x][0]=pre;dfn[x]=++tim;id[tim]=x;
        for (int i=1;i<25;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
        for (int i=head[x];i;i=edge[i].nxt)
        {
            int y=edge[i].to;
            if (y==pre) continue;
            dep[y]=dep[x]+1;
            dfs(y,x);
            sz[x]+=sz[y];
        }
    }
    void add(int x,ll y)
    {
        while (x<=n)
        {
            t[x]+=y;
            x+=x&-x;
        }
    }
    ll sum(int x)
    {
        ll re=0;
        while (x)
        {
            re+=t[x];
            x-=x&-x;
        }
        return re;
    }
    int lca(int x,int y)
    {
        if (dep[x]<dep[y]) swap(x,y);
        for (int i=24;i>=0;i--) if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
        if (x==y) return x;
        for (int i=24;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    bool cmp(int a,int b){return dfn[a]<dfn[b];}
    int main()
    {
        freopen("kaihuang.in","r",stdin);
        freopen("kaihuang.out","w",stdout);
        n=read();Q=read();
        for (int i=1;i<=n;i++) val[i]=read();
        for (int i=1,u,v;i<n;i++)
        {
            u=read();v=read();
            link(u,v);link(v,u);
        }
        dep[1]=1;dfs(1,0);
        //for (int i=1;i<=n;i++) printf("%d ",sz[i]);
        //printf("
    ");
        for (int i=1;i<=n;i++)
        {
            add(dfn[i],val[i]);add(dfn[i]+sz[i],-val[i]);
        }
        char op[5];
        for (int i=1;i<=Q;i++)
        {
            scanf("%s",op);
            if (op[0]=='C')
            {
                int x=read();ll y=read();
                add(dfn[x],-val[x]);add(dfn[x]+sz[x],val[x]);
                val[x]=y;
                add(dfn[x],y);add(dfn[x]+sz[x],-y);
            }
            if (op[0]=='Q')
            {
                int k=0;
                while (1)
                {
                    int x=read();
                    if (!x) break;
                    a[++k]=x;
                }
                sort(a+1,a+1+k,cmp);
                if (k==1)
                {
                    printf("%lld
    ",val[a[1]]);
                    continue;
                }
                ll re=sum(dfn[a[1]]);int LCA=a[1];
                for (int i=2;i<=k;i++)
                {
                    LCA=lca(LCA,a[i]);
                    re+=sum(dfn[a[i]]);
                    re-=sum(dfn[lca(a[i],a[i-1])]);
                }
                re-=sum(dfn[fa[LCA][0]]);
                printf("%lld
    ",re);
            }
        }
        return 0;
    }
  • 相关阅读:
    Boost练习程序(program_options)
    vim一般设置
    删除文件夹及其子文件
    linux搜索一个文件
    窗口最大最小化
    3dmax 学习
    打造个人电脑安全终极防线
    Cacls Command Question
    vc++学习(六)——代码学习
    学习3dmax(四)
  • 原文地址:https://www.cnblogs.com/xxzh/p/9801798.html
Copyright © 2011-2022 走看看