线!线!线!线段树

终于学到线段树了,以前看见很多这样的题,然后暴力,然后TTTTTT了,,,,
我并不打算写了,不过我看到一个非常好的博客,推荐给初学者
http://www.cnblogs.com/TenosDoIt/p/3453089.html#a
特别好玩!!!
最简单的板子(建树,区间最小(大)值,区间和,单节点更新,区间更新)
这里写图片描述
以0为根节点表示的是整个区间,向左右分叉,左面是左区间,右面是右区间
然后重复以上过程直到查到单个数才回溯,从而变成如上图的样子。

/*****最值*****/
void change(int root,int x,int k)//单点修改
{
    int l=e[root].l;
    int r=e[root].r;
    int mid=(l+r)/2;
    if(l==r)
    {
        e[root].sum+=k;
        return ;
    }
    if(x<=mid)
        change(root<<1,x,k);
    else
        change(root<<1|1,x,k);
    e[root].sum=e[root<<1].sum+e[root<<1|1].sum;
}
int query(int root,int ql,int qr)//区间查询(求最值)
{
    int l=e[root].l,r=e[root].r;
    int mid=(l+r)/2;
    int ans=-1;
    if(ql<=l&&r<=qr)
    {
        return e[root].maxx;
    }
    if(ql<=mid)
        ans=max(ans,query(root<<1,ql,qr));
    if(mid<qr)
        ans=max(ans,query(root<<1|1,ql,qr));
    return ans;
}

/*****求和********/
void pushdown(int root)//求和更新
{
    if(e[root].flag)
    {
        int l=e[root].l,r=e[root].r;
        int mid=(l+r)/2;
        e[root<<1].sum+=(e[root].flag*(mid-l+1));
        e[root<<1].flag+=e[root].flag;//应该是+,易错
        e[root<<1|1].sum+=(e[root].flag*(r-mid));
        e[root<<1|1].flag+=e[root].flag;
        e[root].flag=0;
    }
}
int query(int root,int ql,int qr)//区间查询(求和)
{
    int l=e[root].l;
    int r=e[root].r;
    int mid=(l+r)/2;
    if(ql<=l&&r<=qr)
        return e[root].sum;
    int ans=0;
    pushdown(root);//看是否需要
    if(ql<=mid)
        ans+=query(root<<1,ql,qr);
    if(mid<qr)
        ans+=query(root<<1|1,ql,qr);
    return ans;
}
void update(int root,int ql,int qr,int k)//区间更新(求和)
{
    int l=e[root].l,r=e[root].r;
    int mid=(l+r)/2;
    if(ql<=l&&r<=qr)
    {
        e[root].sum+=k*(r-l+1);
        e[root].flag+=k;
        return ;
    }
    pushdown(root);
    if(ql<=mid)
        update(root<<1,ql,qr,k);
    if(mid<qr)
        update(root<<1|1,ql,qr,k);
    e[root].sum=e[root<<1].sum+e[root<<1|1].sum;//更新回溯
}
/******区间染色*****/
int ro[maxn];
int vis[maxn];
int ans;
void pushdown(int root)
{
    if(ro[root]!=-1)
    {
        ro[root<<1]=ro[root];
        ro[root<<1|1]=ro[root];
        ro[root]=-1;
    }
}
void update(int root,int l,int r,int ql,int qr,int k)
{
    if(ql<=l&&r<=qr)
    {
        ro[root]=k;
        return ;
    }
    pushdown(root);
    int mid=(l+r)/2;
    if(mid>=ql) update(root<<1,l,mid,ql,qr,k);
    if(mid<qr) update(root<<1|1,mid+1,r,ql,qr,k);
}
void query(int root,int l,int r)
{
    if(ro[root]!=-1)
    {
        int k=ro[root];
        if(!vis[k])
        {
            ans++;
            vis[k]=1;
        }
        return ;
    }
    if(l==r) return ;
    int mid=(l+r)/2;
    query(root<<1,l,mid);
    query(root<<1|1,mid+1,r);
}
int l[maxn],r[maxn];
int m[maxn];
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        memset(m,0,sizeof(m));
        memset(ro,-1,sizeof(ro));
        memset(vis,0,sizeof(vis));
        ans=0;
        int tot=0;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&l[i],&r[i]);
            m[tot++]=l[i];
            m[tot++]=r[i];
        }
        sort(m,m+tot);
        tot=unique(m,m+tot)-m;
        //防止出现1 10,1 4,7 10这样的样例,所以才有下一步
        for(int i=tot-1;i>=1;i--)
        {
            if(m[i]-m[i-1]>1)
                m[tot++]=m[i-1]+1;
        }
        sort(m,m+tot);
        for(int i=0;i<n;i++)
        {
            int ll=lower_bound(m,m+tot,l[i])-m;
            int rr=lower_bound(m,m+tot,r[i])-m;
            update(1,1,tot,ll+1,rr+1,i+1);
        }
        query(1,1,tot);
        printf("%d\n",ans);
    }
    return 0;
}
/*****矩形并求总面积*****/
double x1,yy1,x2,y2;
double m[maxn];
struct node
{
    double l,r,h;
    int k;
} e[maxn];
int cmp(node x,node y)
{
    return x.h<y.h;
}
struct nodee
{
    int l,r,w;
    double len;
} tree[maxn];
void build(int root,int l,int r)
{
    tree[root].l=l,tree[root].r=r;
    tree[root].len=0.0,tree[root].w=0;
    if(l==r) return ;
    int mid=(l+r)/2;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
}
void bac(int root)
{
    int l=tree[root].l-1,r=tree[root].r;//r不减1把缺失的区间找回来
    if(tree[root].w)
    {
        tree[root].len=m[r]-m[l];
    }
    else if(tree[root].l==tree[root].r)//注意
        tree[root].len=0;
    else
        tree[root].len=tree[root<<1].len+tree[root<<1|1].len;
}
void update(int root,int ql,int qr,int x)
{
    int l=tree[root].l,r=tree[root].r;
    if(ql<=l&&r<=qr)
    {
        tree[root].w+=x;
        bac(root);
        return ;
    }
    int mid=(l+r)/2;
    if(mid>=ql) update(root<<1,ql,qr,x);
    if(mid<qr) update(root<<1|1,ql,qr,x);
    bac(root);
}
int main()
{
    int n;
    int tt=1;
    while(~scanf("%d",&n)&&n)
    {
        int tot=0;
        for(int i=0; i<n; i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&yy1,&x2,&y2);
            e[tot].l=x1;
            e[tot].r=x2;
            e[tot].h=yy1;
            e[tot].k=1;
            m[tot++]=x1;

            e[tot].l=x1;
            e[tot].r=x2;
            e[tot].h=y2;
            e[tot].k=-1;
            m[tot++]=x2;
        }
        sort(e,e+tot,cmp);
        sort(m,m+tot);
        tot=unique(m,m+tot)-m;
        build(1,1,tot);
        double ans=0.0;
        for(int i=0; i<2*n-1; i++)
        {
            int ll=lower_bound(m,m+tot,e[i].l)-m;
            int rr=lower_bound(m,m+tot,e[i].r)-m;
            update(1,ll+1,rr,e[i].k);//rr不加1避免区间缺失
            ans+=(e[i+1].h-e[i].h)*tree[1].len;
        }
        printf("Test case #%d\n",tt++);
        printf("Total explored area: %.2lf\n\n",ans);
    }
    return 0;
}
/*****矩形并求叠加层数为2的*****/
double x1,yy1,x2,y2;
double m[maxn];
struct node
{
    double l,r,h;
    int k;
} e[maxn];
int cmp(node x,node y)
{
    return x.h<y.h;
}
struct nodee
{
    int l,r,w;
    double len,lenn;
} tree[maxn];
void build(int root,int l,int r)
{
    tree[root].l=l,tree[root].r=r;
    tree[root].len=0.0;
    tree[root].w=0;
    tree[root].lenn=0.0;
    if(l==r) return ;
    int mid=(l+r)/2;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
}
void bac(int root)
{
    int l=tree[root].l-1,r=tree[root].r;//r不减1把缺失的区间找回来
    if(tree[root].w)
        tree[root].len=m[r]-m[l];
    else if(tree[root].l==tree[root].r)
        tree[root].len=0;
    else
        tree[root].len=tree[root<<1].len+tree[root<<1|1].len;

    if(tree[root].w>1)
        tree[root].lenn=m[r]-m[l];
    else if(tree[root].l==tree[root].r)
        tree[root].lenn=0;
    else if(tree[root].w==1)
        tree[root].lenn=tree[root<<1].len+tree[root<<1|1].len;
    else
        tree[root].lenn=tree[root<<1].lenn+tree[root<<1|1].lenn;
}
void update(int root,int ql,int qr,int x)
{
    int l=tree[root].l,r=tree[root].r;
    if(ql<=l&&r<=qr)
    {
        tree[root].w+=x;
        bac(root);
        return ;
    }
    int mid=(l+r)/2;
    if(mid>=ql) update(root<<1,ql,qr,x);
    if(mid<qr) update(root<<1|1,ql,qr,x);
    bac(root);
}
int main()
{
    int t,n;
    int tt=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        memset(m,0,sizeof(m));
        int tot=0;
        for(int i=0; i<n; i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&yy1,&x2,&y2);
            e[tot].l=x1;
            e[tot].r=x2;
            e[tot].h=yy1;
            e[tot].k=1;
            m[tot++]=x1;

            e[tot].l=x1;
            e[tot].r=x2;
            e[tot].h=y2;
            e[tot].k=-1;
            m[tot++]=x2;
        }
        sort(e,e+tot,cmp);
        sort(m,m+tot);
        tot=unique(m,m+tot)-m;
        build(1,1,tot);
        double ans=0.0;
        for(int i=0; i<2*n-1; i++)
        {
            int ll=lower_bound(m,m+tot,e[i].l)-m;
            int rr=lower_bound(m,m+tot,e[i].r)-m;
            update(1,ll+1,rr,e[i].k);//rr不加1避免区间缺失
            ans+=(e[i+1].h-e[i].h)*tree[1].lenn;
        }
        printf("%.2lf\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值