BOI2007 Mokia 摩基亚

题目描述

题解:

容斥,将询问变成4个加权询问。

然后就是cdq了。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 200050
#define ll long long
inline int rd()
{
    int f=1,c=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();}
    return f*c;
}
int typ,w,tim=1,cnt;
struct node
{
    int x,y,t,w,k;
    node(){}
    node(int t,int w,int k):t(t),w(w),k(k){}
}p[N],tmp[N];
struct xy
{
    int x,id;
    xy(){}
    xy(int x,int i):x(x),id(i){}
}X[N],Y[N];
bool cmp(xy a,xy b)
{
    return a.x<b.x;
}
ll ans[N];
struct BIT
{
    ll v[N];
    void up(int x,ll d)
    {
        if(!x)return ;
        while(x<N)
            v[x]+=d,x+=(x&-x);
    }
    ll down(int x)
    {
        if(!x)return 0;
        ll ret = 0ll;
        while(x)
            ret+=v[x],x-=(x&-x);
        return ret;
    }
}tr;
void Sort(int l,int r)
{
    int mid = (l+r)>>1;
    int i=l,j=mid+1,k=l;
    while(i<=mid&&j<=r)
    {
        while(i<=mid&&p[i].x<=p[j].x)
        {
            tmp[k]=p[i];
            i++,k++;
        }
        while(j<=r&&p[i].x>p[j].x)
        {
            tmp[k]=p[j];
            j++,k++;
        }
    }
    while(i<=mid)tmp[k]=p[i],i++,k++;
    while(j<=r)tmp[k]=p[j],j++,k++;
    for(i=l;i<=r;i++)p[i]=tmp[i];
}
int kkk[N],ct;
void cdq(int l,int r)
{
    if(l==r)return ;
    int mid = (l+r)>>1;
    cdq(l,mid),cdq(mid+1,r);
    Sort(l,mid),Sort(mid+1,r);
    int i,j;
    for(i=mid+1,j=l;i<=r;i++)
    {
        while(j<=mid&&p[j].x<=p[i].x)
            tr.up(p[j].y,p[j].w),j++;
        if(p[i].k)
            ans[kkk[p[i].t]]+=p[i].k*tr.down(p[i].y);
    }
    for(j=j-1;j>=l;j--)tr.up(p[j].y,-p[j].w);
}
int main()
{
    while(scanf("%d",&typ))
    {
        if(typ==0)
        {
            w=rd();
        }else if(typ==1)
        {
            int x=rd(),y=rd(),A=rd();
            p[++cnt]=node(tim,A,0);X[cnt]=xy(x,cnt);Y[cnt]=xy(y,cnt);
        }else if(typ==2)
        {
            int lx = rd(),dy = rd(),rx = rd(),uy = rd();
            tim++;ct++;kkk[tim]=ct;
            p[++cnt]=node(tim,0,1);X[cnt]=xy(rx,cnt);Y[cnt]=xy(uy,cnt);
            p[++cnt]=node(tim,0,1);X[cnt]=xy(lx-1,cnt);Y[cnt]=xy(dy-1,cnt);
            p[++cnt]=node(tim,0,-1);X[cnt]=xy(lx-1,cnt);Y[cnt]=xy(uy,cnt);
            p[++cnt]=node(tim,0,-1);X[cnt]=xy(rx,cnt);Y[cnt]=xy(dy-1,cnt);
            tim++;
        }else break;
    }
    sort(X+1,X+1+cnt,cmp);
    sort(Y+1,Y+1+cnt,cmp);
    for(int las=-1,k=0,i=1;i<=cnt;i++)
    {
        if(X[i].x!=las)
        {
            las = X[i].x;
            k++;
        }
        p[X[i].id].x = k;
    }
    for(int las=-1,k=0,i=1;i<=cnt;i++)
    {
        if(Y[i].x!=las)
        {
            las = Y[i].x;
            k++;
        }
        p[Y[i].id].y = k;
    }
    tim--;
    cdq(1,cnt);
    for(int i=1;i<=ct;i++)
        printf("%lld\n",ans[i]);
    return 0;
}

 

转载于:https://www.cnblogs.com/LiGuanlin1124/p/10143453.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值