zoukankan      html  css  js  c++  java
  • [2016北京集训试题17]数组-[线段树]

    Description

    Solution

    线段树乱搞orz。

    定义pre[i]为从i点往前找到第1个颜色和点i相同的点。树状数组记录max和sum。max记录区间[l,r]内pre的最大值,sum记录区间[l,r]内的答案总和。注意:最终的答案是取

    $n*(n+1)/2-sum _{r=1}^{n}max(pre[i],1leq ileq r)$,即枚举所有子区间的右节点,找最左的左节点。因此,sum[x](记录区间[l,r])在更新的时候,sum[x的左节点]可以直接加上,而对于x的右节点要保证区间[mid+1,r]的数和max[x的左节点]取最大值。这个可以在log(n)内搞定。

    然后。。就ok了。

    我怕是学了个假的线段树。

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<set>
    using namespace std;
    typedef long long ll;
    const int N=1e5+10;
    int n,m;
    int col[N],pre[N];
    set<int>id[N];
    ll sum[N<<2],mx[N<<2];
    ll solve(int k,int l,int r,ll x)
    {
        if (l==r) return max(x,mx[k]);
        int mid=(l+r)/2;
        if (mx[k]<=x) return x*(r-l+1);
        if (mx[k<<1]<=x) return 1ll*x*(mid-l+1)+solve(k<<1|1,mid+1,r,x);
        return solve(k<<1,l,mid,x)+sum[k]-sum[k<<1];
    }
    void pushup(int k,int mid,int r)
    {
        mx[k]=max(mx[k<<1],mx[k<<1|1]);
        sum[k]=sum[k<<1]+solve(k<<1|1,mid+1,r,mx[k<<1]);
    }
    void modify(int k,int l,int r,int x,int y)
    {
        if (l==r){sum[k]=mx[k]=y;return;}
        int mid=(l+r)/2;
        if (x<=mid) modify(k<<1,l,mid,x,y);else modify(k<<1|1,mid+1,r,x,y);
        pushup(k,mid,r);
    }
    void build(int k,int l,int r)
    {
        if (l==r){sum[k]=mx[k]=pre[l];return;}
        int mid=(l+r)/2;
        build(k<<1,l,mid);build(k<<1|1,mid+1,r);
        pushup(k,mid,r);
    }
    set<int>::iterator q,l,r;
    int x,to;
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++) id[i].insert(0);
        for (int i=1;i<=n;i++) 
        {
            scanf("%d",&col[i]);
            pre[i]=*(--id[col[i]].end());
            id[col[i]].insert(i);
        }
        build(1,1,n);
        int Q,opt;
        scanf("%d",&Q);
        while (Q--)
        {
            scanf("%d",&opt);
            if (!opt) printf("%lld
    ",1ll*n*(n+1)/2-sum[1]);
            else
            {
                scanf("%d%d",&x,&to);
                q=id[col[x]].find(x);
                l=r=q;l--;r++;
                if (r!=id[col[x]].end())
                {
                    pre[*r]=*l;
                    modify(1,1,n,*r,*l);
                }
                id[col[x]].erase(q); 
                col[x]=to;id[to].insert(x);
                q=id[to].find(x);
                l=r=q;l--;r++;
                if (r!=id[to].end())
                {
                    pre[*r]=x;
                    modify(1,1,n,*r,x);
                }
                pre[x]=*l;
                modify(1,1,n,x,*l);
                 
            }
        }
    }
  • 相关阅读:
    AngularJs+bootstrap搭载前台框架——准备工作
    AngularJs+bootstrap搭载前台框架——基础页面
    AngularJs调用Restful实现CRUD
    用AngularJs制作单页面应用
    Unity3D中使用Projector生成阴影
    Linux OpenGL 实践篇-16 文本绘制
    leetcode 233. 数字1的个数
    leetcode 189. 轮转数组
    leetcode 127 单词接龙
    leetcode 4.两个排序数组的中位数
  • 原文地址:https://www.cnblogs.com/coco-night/p/9733342.html
Copyright © 2011-2022 走看看