HDU 5372 Segment Game

在数轴上给你一些线段,每添加一条线段,问完全被它包含的区间的个数。
还有删除操作。线段长度是递增的。
题解用线段长度递增这个特点,可以用树状数组做,具体这样:
算出左端点比当前插入线段的左端点大的数目,再减去右端点比插入的右端点大的数目,由于线段长度是递增的,所以当前一定的答案一定是对的。
然而我用的是cdq分治的方法去做,复杂度nlogn^2,算出前面一半的线段添加对后面线段的查询的贡献减去前面一半删除线段的贡献对查询的贡献就可以了。杭电上是T了,本地跑1.6s,答案对的,排序去优化下正常就可以过了,不过懒。。。。。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <queue>
#include <map>
#include <vector>
#include <string>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cctype>
#include <set>
#include <cmath>
using namespace std;
typedef long long ll;
const int MAXN=4e5+10;
int bits[MAXN];
int L[MAXN];
int ans[MAXN];
int n;
template <class T>
inline bool scan_d(T &ret)
{
    char c;
    int sgn;
    if(c=getchar(),c==EOF) return 0; //EOF
    while(c!='-'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    ret*=sgn;
    return 1;
}
inline void out(int x)
{
    if(x>9) out(x/10);
    putchar(x%10+'0');
}
inline void add(int p,int v)
{
    while(p<=n)
    {
        bits[p]+=v;
        p+=p&-p;
    }
}
inline int sum(int p)
{
    int ans=0;
    while(p)
    {
        ans+=bits[p];
        p-=p&-p;
    }
    return ans;
}
struct AP
{
    int id,v,t;
    bool operator <(const AP &a) const
    {
        if(v!=a.v)    return v<a.v;
        if(t==a.t)
        {
            if(t==0) return id>a.id;
            return id<a.id;
        }
        return t<a.t;
    }
    AP() {}
    AP(int _id,int _v,int _t)
    {
        id=_id,v=_v,t=_t;
    }
} v[MAXN*2],q[MAXN*2];
int a[MAXN],b[MAXN],cnt[MAXN];
int adl[MAXN],adr[MAXN];

void cal(int l,int r)
{
    if(l>=r) return ;
//    cout<<l<<' '<<r<<endl;
    int mid=(l+r)/2;
    cal(l,mid);
    cal(mid+1,r);
    int k=0,c=0;
    for(int i=mid+1; i<=r; i++)
    {
        if(a[i]) continue;
        else
        {
            v[k++]=AP(i,adl[cnt[i]],0);
            v[k++]=AP(i,adr[cnt[i]],1);

            q[c++]=AP(i,adl[cnt[i]],0);
            q[c++]=AP(i,adr[cnt[i]],1);
        }
    }
    for(int i=mid; i>=l; i--)
    {
        if(a[i])
        {
            q[c++]=AP(-i,adl[b[i]],0);
            q[c++]=AP(-i,adr[b[i]],1);
        }
        else
        {
            v[k++]=AP(-i,adl[cnt[i]],0);
            v[k++]=AP(-i,adr[cnt[i]],1);
        }
    }
    sort(v,v+k);
    memset(bits,0,sizeof(int)*(k+1));
    n=k;
    for(int i=0; i<k; i++)
    {
        AP &x=v[i];
        if(x.id>0)
        {
            if(x.t==0) L[x.id]=i+1;
            else
                ans[x.id]+=sum(L[x.id]);
        }
        else
        {
            x.id=-x.id;
            if(x.t==0) L[x.id]=i+1;
            else
            {
                add(1,1);
                add(L[x.id]+1,-1);
            }
        }
    }

    sort(q,q+c);
    memset(bits,0,sizeof(int)*(c+1));
    n=c;
    for(int i=0; i<c; i++)
    {
        AP &x=q[i];
        if(x.id>0)
        {
            if(x.t==0) L[x.id]=i+1;
            else
                ans[x.id]-=sum(L[x.id]);
        }
        else
        {
            x.id=-x.id;
            if(x.t==0) L[x.id]=i+1;
            else
            {
                add(1,1);
                add(L[x.id]+1,-1);
            }
        }
    }
}
int main()
{
//    freopen("/home/sunshine/tests/input","r",stdin);
//    freopen("in","r",stdin);
//    freopen("out","w",stdout);
//    srand(time(NULL));
    int kcase=0;
    int n;
    while(cin>>n)
    {
//        n=rand()%2+1;
        int c=1;
        for(int i=1; i<=n; i++)
        {
//            scan_d(a[i]);
//            scan_d(b[i]);
            scanf("%d%d",a+i,b+i);
            if(a[i]==0)
            {
                adl[c]=b[i];
                adr[c]=b[i]+c;
                cnt[i]=c;
                c++;
            }
        }
        fill(ans,ans+n+1,0);
        cal(1,n);
//        bool xk=false;
//        if(test(n)==false)
//        {
//            for(int i=1;i<=n;i++)
//                cout<<a[i]<<' '<<b[i]<<' '<<ans[i]<<endl;
//            xk=true;
//        }
        printf("Case #%d:\n",++kcase);
        for(int i=1; i<=n; i++)
        {
            if(a[i]==0)
            {
                out(ans[i]);
                putchar(10);
//                printf("%d\n",ans[i]);
            }
        }
//        if(xk) break;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值