zoukankan      html  css  js  c++  java
  • 【线段树】牛客国庆day3(2018hncpc) E. Grid 线段树

    Grid

    这是跟平时不太一样的线段树。

    这道题要用是要线段树记录区间(线段),然后判断  当前所记录的  所有线段  总共覆盖的长度,也就是说,线段可能会重叠,重叠的区间长度不能重复计算,要计算实际得到的  所有线段的长度。

    想想 怎么记录? 跟平时一样的话,我大概就是,把线段分为单个单个点,然后把区间标记为1,然后计算的时候就,到了标记为1的区间,就直接ans+=r-l+1,但是,因为是分散的区间线段,搜索时间会大于平时。有点不足,也不知道有没有别的做法。

    但是,这道题还不能用这种做法,因为区间长度是1e9,需要离散。

    所以看了别人的做法:离散询问出现的点的坐标,然后,线段是[l,r],把线段树的[l,r]的值置为h[r]-h[l],这个也不是我想说的重点。

    但是,离散了之后,mid和mid+1的值就断开了,这样子 两个区间的值不就不连续了吗?会缺少[h[mid],h[mid+1]]的值。

    所以看了别人的做法:线段树的左右子树的区间是[l,mid] [mid,r],或者  更准确的说是,传递到左右子树的离散数组区间是[ h[l],h[mid] ]和[ h[mid],h[r] ] ,这样子就能解决~...了吗?有个小细节忘了说 线段区间[val[l],val[r]]的长度并不是真实的h[r]-h[l],在记录r的时候 h[r]的值实际是val[r+1],这样才满足区间的真实长度(r-l+1)嘛。

    想无,记下来。

    代码:

    #include<bits/stdc++.h>
    #include<tr1/unordered_map>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int maxn=1e5+50;
    const int mod=1e9+7;
    const int inf=0x3f3f3f3f;
    
    struct P{
        int ly;ll sum;
    }tree1[maxn<<3],tree2[maxn<<3];
    
    int h[maxn<<1],tot,nn,mm;
    int val(int v)
    {
        return lower_bound(h+1,h+1+tot,v)-h;
    }
    
    
    void down(int k,int L,int R,P tree[])
    {
        int mid=(L+R)>>1;
        tree[k<<1].sum=h[mid]-h[L];
        tree[k<<1|1].sum=h[R]-h[mid];
        tree[k<<1].ly=1;
        tree[k<<1|1].ly=1;
        tree[k].ly=0;
    }
    
    void update(int k,int L,int R,int l,int r,P tree[])
    {
        if(l==L&&R==r)
        {
            tree[k].sum=h[r]-h[l];
            tree[k].ly=1;
            return ;
        }
        if(tree[k].ly)down(k,L,R,tree);
        int mid=(L+R)>>1;
        if(r<=mid)update(k<<1,L,mid,l,r,tree);
        else if(l>=mid)update(k<<1|1,mid,R,l,r,tree);
        else
        {
            update(k<<1,L,mid,l,mid,tree);
            update(k<<1|1,mid,R,mid,r,tree);
        }
        tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
    }
    
    struct Q{
        int op,a,b;
    }p[maxn];
    
    int main()
    {
        ll n,m;
        ll ans,t;
        int q,op,a,b;
        while(~scanf("%lld%lld%d",&n,&m,&q))
        {
            tot=0;
            for(int i=1;i<=q;i++)
            {
                scanf("%d%d%d",&p[i].op,&p[i].a,&p[i].b);
                h[++tot]=p[i].a;h[++tot]=p[i].b+1;
            }
            h[++tot]=n+1;h[++tot]=m+1;
            sort(h+1,h+1+tot);
            tot=unique(h+1,h+1+tot)-h-1;
            nn=val(n+1);mm=val(m+1);
            for(int i=1;i<=tot*4;i++)
            {
                tree1[i].sum=tree1[i].ly=0;
                tree2[i].sum=tree2[i].ly=0;
            }
            for(int i=1;i<=q;i++)
            {
                a=val(p[i].a);b=val(p[i].b+1);
                if(p[i].op==1)update(1,1,nn,a,b,tree1);
                else update(1,1,mm,a,b,tree2);
                ans=(n*m)-(tree1[1].sum*m+tree2[1].sum*n)+(tree1[1].sum*tree2[1].sum);
                if(tree1[1].sum==0)ans+=tree2[1].sum;
                else if(tree2[1].sum==0)ans+=tree1[1].sum;
                else ans++;
                printf("%lld
    ",ans);
            }
        }
    }

    但是!!!但是,更好的做法是:动态开点线段树

    但是!!!但是,在牛客这样做会超内存。等国庆过后去别的oj补题。

    #include<bits/stdc++.h>
    #include<tr1/unordered_map>
    #define debug printf("!");
    using namespace std;
    typedef long long ll;
    const int maxn=1e5+5;
    const int mod=1e9+7;
    const int inf=0x3f3f3f3f;
    
    int sum1[maxn<<3],L1[maxn<<3],R1[maxn<<3],cnt1,T1;
    int sum2[maxn<<3],L2[maxn<<3],R2[maxn<<3],cnt2,T2;
    
    void init()
    {
        for(int i=0;i<=cnt1;i++)sum1[i]=L1[i]=R1[i]=0;
        for(int i=0;i<=cnt2;i++)sum2[i]=L2[i]=R2[i]=0;
        cnt1=cnt2=0;
    }
    
    void update1(int &rt,int l,int r,int tl,int tr)
    {
        if(!rt)rt=++cnt1;
        if(sum1[rt]==r-l+1)return;
        if(tl<=l&&r<=tr)
        {
            sum1[rt]=r-l+1;return;
        }
        int mid=(l+r)>>1;
        if(tl<=mid)update1(L1[rt],l,mid,tl,tr);
        if(tr>mid)update1(R1[rt],mid+1,r,tl,tr);
        sum1[rt]=sum1[L1[rt]]+sum1[R1[rt]];
    }
    void update2(int &rt,int l,int r,int tl,int tr)
    {
        if(!rt)rt=++cnt2;
        if(sum2[rt]==r-l+1)return;
        if(tr<=l&&r<=tr)
        {
            sum2[rt]=r-l+1;return;
        }
        int mid=(l+r)>>1;
        if(tl<=mid)update2(L2[rt],l,mid,tl,tr);
        if(tr>mid)update2(R2[rt],mid+1,r,tl,tr);
        sum2[rt]=sum2[L2[rt]]+sum2[R2[rt]];
    }
    int main()
    {
        ll n,m;
        ll ans,t;
        int q,op,a,b;
        while(~scanf("%lld%lld%d",&n,&m,&q))
        {
            init();
            while(q--)
            {
                scanf("%d%d%d",&op,&a,&b);
                if(op==1)update1(T1,1,n,a,b);
                else update2(T2,1,m,a,b);
                ans=n*m-((ll)sum1[1]*m+(ll)sum2[1]*n)+(ll)sum1[1]*(ll)sum2[1];
                if(sum1[1]==0)ans+=sum2[1];
                else if(sum2[1]==0)ans+=sum1[1];
                else ans++;
                printf("%lld
    ",ans);
            }
        }
    }
  • 相关阅读:
    iOS-关于博客园博客到简书平台的迁移
    iOS-工作经验+资料分享(长期更新)
    iOS-公司开发者账号的申请和注册(原创+亲身+2016年申请+附带与邓白氏公司的往来邮件截图)
    iOS-HTML-02
    iOS-HTML-01
    iOS-保存照片或者视频到自定义相薄中以及读取数据
    iOS-UITableView的优化(纯手打原创)
    iOS-多线程之GCD(原创)
    iOS-绘图(Quartz2D)的简单使用(原创)
    iOS-Cocoapods
  • 原文地址:https://www.cnblogs.com/kkkek/p/11621399.html
Copyright © 2011-2022 走看看