• BZOJ5110 CodePlus2017Yazid 的新生舞会(线段树)


      考虑统计每个数字的贡献。设f[i]为前缀i中该数的出现次数,则要统计f[r]-f[l]>(r-l)/2的数对个数,也即2f[r]-r>2f[l]-l。

      注意到所有数的f的总变化次数是线性的,考虑对每次变化进行统计。

      对于当前考虑位置i,统计r∈[i,nxt[a[i]])时a[i]的贡献。如果将之前的所有2f[l]-l扔进一个线段树里,可以发现要统计的是终点在一段区间内的前缀和的和。那么不属于该区间的每个2f[l]-l都会被统计nxt[a[i]]-i次,属于该区间的2f[l]-l的被统计次数构成一个等差数列,维护区间和的同时再维护区间前缀和的和即可。统计完后把这段作为l的贡献加进去,就是一个线段树区间加。

      写的是动态开点,然而在下传标记的时候忘记开新点了,于是浪费了两个小时宝贵的人生。bzoj上T掉了然而没心情卡常了。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 500010
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int n,a[N],nxt[N],p[N],f[N],cnt,root[N];
    ll ans=0;
    struct data{int l,r,sum,lazy;ll pre;
    }tree[N*35];
    void update(int &k,int l,int r,int x)
    {
        if (!k) k=++cnt;
        tree[k].sum+=(r-l+1)*x;
        tree[k].pre+=1ll*x*(r-l+1)*(r-l+2)>>1;
        tree[k].lazy+=x;
    }
    void down(int k,int l,int r)
    {
        update(tree[k].l,l,l+r>>1,tree[k].lazy),update(tree[k].r,(l+r>>1)+1,r,tree[k].lazy);
        tree[k].lazy=0;
    }
    int querys(int k,int l,int r,int x,int y)
    {
        if (!k) return 0;
        if (l==x&&r==y) return tree[k].sum;
        if (tree[k].lazy) down(k,l,r);
        int mid=l+r>>1;
        if (y<=mid) return querys(tree[k].l,l,mid,x,y);
        else if (x>mid) return querys(tree[k].r,mid+1,r,x,y);
        else return querys(tree[k].l,l,mid,x,mid)+querys(tree[k].r,mid+1,r,mid+1,y);
    }
    ll querypre(int k,int l,int r,int x,int y)
    {
        if (!k) return 0;
        if (l==x&&r==y) return tree[k].pre;
        if (tree[k].lazy) down(k,l,r);
        int mid=l+r>>1;
        if (y<=mid) return querypre(tree[k].l,l,mid,x,y);
        else if (x>mid) return querypre(tree[k].r,mid+1,r,x,y);
        else return querypre(tree[k].l,l,mid,x,mid)+querypre(tree[k].r,mid+1,r,mid+1,y)+1ll*querys(tree[k].l,l,mid,x,mid)*(y-mid);
    }
    void ins(int &k,int l,int r,int x,int y)
    {
        //cout<<l-n<<' '<<r-n<<' '<<x-n<<' '<<y-n<<endl;
        if (!k) k=++cnt;
        if (l==x&&r==y) {update(k,l,r,1);return;}
        if (tree[k].lazy) down(k,l,r);
        int mid=l+r>>1;
        if (y<=mid) ins(tree[k].l,l,mid,x,y);
        else if (x>mid) ins(tree[k].r,mid+1,r,x,y);
        else ins(tree[k].l,l,mid,x,mid),ins(tree[k].r,mid+1,r,mid+1,y);
        tree[k].sum=tree[tree[k].l].sum+tree[tree[k].r].sum;
        tree[k].pre=tree[tree[k].l].pre+tree[tree[k].r].pre+1ll*tree[tree[k].l].sum*(r-mid);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj5110.in","r",stdin);
        freopen("bzoj5110.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read();read();
        for (int i=1;i<=n;i++)
        {
            a[i]=read()+1;
            if (!p[a[i]]) ins(root[a[i]],0,n*2,n+1-i,n);
            nxt[p[a[i]]]=i,p[a[i]]=i;
        }
        for (int i=1;i<=n;i++) if (!nxt[i]) nxt[i]=n+1;
        for (int i=1;i<=n;i++)
        {
            f[a[i]]++;
            int x=2*f[a[i]]-(nxt[i]-1),y=2*f[a[i]]-i;
            ans+=1ll*querys(root[a[i]],0,n*2,0,n+x-2)*(y-x+1);
            ans+=querypre(root[a[i]],0,n*2,n+x-1,n+y-1);
            ins(root[a[i]],0,n*2,x+n,y+n);
        }
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    144. Binary Tree Preorder Traversal
    excel 文本拼接
    excel中文转拼音(方便复制版本)
    odoo 日志文件太大处理,logfile自动轮替
    编码对象或者字串中包含Unicode字符怎样转换为中文
    odoo 返回成功提示信息
    odoo 对res_partner,res_users添加字段重启服务失败处理
    odoo 根据当前记录的值动态筛选many2many,many2one,one2many数据
    odoo 中%()d的使用
    nginx 监听非标准端口80,重定向端口丢失问题解决
  • 原文地址:https://www.cnblogs.com/Gloid/p/9897952.html
Copyright © 2020-2023  润新知