zoukankan      html  css  js  c++  java
  • SHOI2013 扇形面积并

    题目链接:戳我

    补一张图

    我们尝试把圆上的扇形转化成直线上的矩形——我们维护[1,2m]的区间,那么每个能产生贡献的子区间的长度第K大的半径的平方的总和就是answer了。

    怎么转化呢?左端点为a1+m+1,右端点为a2+m。为什么要+m?因为原先的范围是[-m,m]的,所以整体右移。为什么左端点要+1?因为我们维护的是区间,所以这里的每一个下标表示的是以该position为右端点,长度为1的区间。

    我们先按照半径长度从大到小排序,如果一个区间覆盖数量超过K个,就不需要再处理了。(优化时间复杂度)

    之后就是线段树操作了。我们在更改的同时求出答案。(其实分开写也行,就是要注意因为我们乘上的系数使然,所以区间必须也是当前的修改区间)

    minn表示该区间的所有子区间覆盖量的min,maxx是该区间的所有子区间的覆盖量的max。

    注意我们的siz是由左右子区间合并而来的。所以产生贡献之后,记得赋值为0,这样就不会对它的父亲区间产生贡献了。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 2000010
    using namespace std;
    int n,m,k;
    long long ans=0;
    struct Node{int l,r,c;}node[MAXN];
    struct Node2{int l,r,tag,minn,maxx,siz;}t[MAXN<<2];
    inline bool cmp(struct Node x,struct Node y){return x.c>y.c;}
    inline int ls(int x){return x<<1;}
    inline int rs(int x){return x<<1|1;}
    inline void push_up(int x)
    {
        t[x].maxx=max(t[ls(x)].maxx,t[rs(x)].maxx);
        t[x].minn=min(t[ls(x)].minn,t[rs(x)].minn);
        t[x].siz=t[ls(x)].siz+t[rs(x)].siz;
    }
    inline void build(int x,int l,int r)
    {
        t[x].l=l,t[x].r=r;
        if(l==r) {t[x].siz=1;return;}
        int mid=(l+r)>>1;
        build(ls(x),l,mid);
        build(rs(x),mid+1,r);
        push_up(x);
    }
    inline void solve(int x,int k)
    {
        t[x].tag+=k;
        t[x].minn+=k;
        t[x].maxx+=k;
    }
    inline void push_down(int x)
    {
        int l=t[x].l,r=t[x].r;
        if(t[x].tag)
        {
            solve(ls(x),t[x].tag);
            solve(rs(x),t[x].tag);
            t[x].tag=0;
        }
    }
    inline int update_query(int x,int ll,int rr)
    {
        int l=t[x].l,r=t[x].r;
        if(t[x].minn>=k) return 0;
        if(ll<=l&&r<=rr)
        {
            if(t[x].maxx<k-1) {t[x].minn++,t[x].maxx++,t[x].tag++;return 0;}
            if(t[x].minn>=k-1) 
            {
                int cur_ans=t[x].siz;
                t[x].siz=0;
                t[x].minn++;
                return cur_ans;
            } 
            int cur_ans=0;
            push_down(x);
            cur_ans+=update_query(ls(x),ll,rr);
            cur_ans+=update_query(rs(x),ll,rr);
            push_up(x);
            return cur_ans;
        }
        push_down(x);
        int mid=(l+r)>>1;
        int cur_ans=0;
        if(ll<=mid) cur_ans+=update_query(ls(x),ll,rr);
        if(mid<rr) cur_ans+=update_query(rs(x),ll,rr);
        push_up(x);
        return cur_ans;
    }
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++) 
        {
            scanf("%d%d%d",&node[i].c,&node[i].l,&node[i].r);
            node[i].l+=m+1;
            node[i].r+=m;
        }
        sort(&node[1],&node[n+1],cmp);
        build(1,1,m*2);
        for(int i=1;i<=n;i++)
        {
            int cur_ans=0;
            if(node[i].l<node[i].r)
                cur_ans+=update_query(1,node[i].l,node[i].r);
            else if(node[i].l>node[i].r)
            {
                cur_ans+=update_query(1,node[i].l,m*2);
                cur_ans+=update_query(1,1,node[i].r);
            }
            ans+=1ll*cur_ans*node[i].c*node[i].c;
            //printf("i=%d ans=%lld
    ",i,ans);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    7、shell函数
    5、shell分支
    6、shell循环
    4、shell中的test命令
    3、shell中引号
    2、shell变量
    1、建立和运行shell
    awk命令简介
    18、异步IO
    Python模块:sys
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10491784.html
Copyright © 2011-2022 走看看