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\n",i,ans);
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2019-03-08 07:48  风浔凌  阅读(222)  评论(0编辑  收藏  举报