zoukankan      html  css  js  c++  java
  • 乱搞 [CodeForces 348C] Subset Sums nsqrtn

    题面去内网找
    这道题的思路很神奇,把集合分成了重集合和轻集合。我们把元素个数大于sqrt(n)的集合称为重集合。显然这样的集合超不过sqrt(n)个。
    那么就可以分别处理集合了
    首先统计出每个集合与每一个重集合交集有多大。维护重集合的sum(总和)和add(这个集合累计加了多少)值。
    对于重集合
    1.修改:只改一下add就好
    2.查询:sum[x]+add所有重集合×与其交集
    对于轻集合
    1.修改:暴力。
    2查询:暴力加+那一堆add
    其实这道题的灵感来源于树链剖分的轻重之分

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #define N 100005
    #define ll long long
    using namespace std;
    struct road{int v,next;}lu[N*4];
    int n,m,q,h,e,tot,ss[N],adj1[N],adj2[N],vis[N];
    ll a[N],cnt[N][320],sum[320],add[320];
    void add1(int u,int v){lu[++e]=(road){v,adj1[u]};adj1[u]=e;}
    void add2(int u,int v){lu[++e]=(road){v,adj2[u]};adj2[u]=e;}
    int main()
    {
        //freopen("20.in","r",stdin);
        //freopen(".out","w",stdout);
        scanf("%d%d%d",&n,&m,&q);ll x,y,z;h=sqrt(n);
        for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
        for(int i=1;i<=m;i++)
        {
            scanf("%lld",&y);
            if(y>=h)++tot,vis[i]=1,ss[i]=tot;
            for(int j=1;j<=y;j++)
            {
                scanf("%lld",&x),add1(i,x);
                if(vis[i]==1)sum[ss[i]]+=a[x],add2(x,ss[i]);
            }
        }
        for(int i=1;i<=m;i++)
            for(int k=adj1[i];k;k=lu[k].next)
            {
                int to=lu[k].v;
                for(int j=adj2[to];j;j=lu[j].next)
                    cnt[i][lu[j].v]++;
            }
        ll ans=0;
        while(q--)
        {
            scanf("%lld",&z);
            if(z==1)
            {
                scanf("%lld",&x);ans=0;
                if(!vis[x])
                {
                    for(int i=adj1[x];i;i=lu[i].next)ans+=a[lu[i].v];
                    for(int i=1;i<=tot;i++)ans+=add[i]*cnt[x][i];
                }
                else
                {
                    ans=sum[ss[x]];
                    for(int i=1;i<=tot;i++)ans+=add[i]*cnt[x][i];
                }
                printf("%lld
    ",ans);
            }
            else
            {
                scanf("%lld%lld",&x,&y);
                if(!vis[x])
                {
                    for(int i=adj1[x];i;i=lu[i].next)a[lu[i].v]+=y;
                    for(int i=1;i<=tot;i++)sum[i]+=y*cnt[x][i];
                }
                else add[ss[x]]+=y;
            }
        }
    }
  • 相关阅读:
    Solaris+Oracle安装(详细图解)
    linux卸载和安装jdk
    UTF8, Unicode, GB2312格式串转换之C语言版
    linux安装ant
    在 Linux 平台下使用 JNI
    华为C/C++笔试题(1)
    c面试
    mongodb数据库
    YARN
    NPM(包管理器)
  • 原文地址:https://www.cnblogs.com/QTY2001/p/7674423.html
Copyright © 2011-2022 走看看