HDU 5372 Segment Game - 离散化&树状数组

题目描述

表示看错题目的一小部分,wa了两个小时!!!

题目大意:

有 n 个操作,每次要么插入一条线段,要么删除一条已存在的线段,其中第 i 次插入的线段的长度为 i。
对于每次插入,输出当前插入的线段能完整覆盖多少条线 段。
1 ≤n≤ 700000。
Source:2015 Multi-University Training Contest 7

分析(From Claris):

  • 其实就是询问左端点在 l 右侧且右端点在 r 左侧的线段数。
  • CDQ 分治?树套树?O(nlog2n) 的复杂度并不能承受。
  • ans = 左端点在 l 右侧的线段数 − 左端点在 l 右侧且右端点 在 r 右侧的线段数。
  • 因为线段长度递增,所以之前线段如果右端点在 r 右侧,那 么左端点一定在 l 右侧。
  • 故 ans = 左端点在 l 右侧的线段数 − 右端点在 r 右侧的线 段数。两棵树状数组维护即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 200000

int n,b[MAXN*2+10],cntb,qua[MAXN+10][3],add[MAXN+10],cntad,c1[MAXN*2+10],c2[MAXN*2+10],sum1,sum2;

void Init()
{
    memset(b,0,sizeof b);
    memset(c1,0,sizeof c1);
    memset(c2,0,sizeof c2);
    cntad=cntb=0;
    sum1=sum2=0;
}
void read()
{
    for(int i=1;i<=n;i++){
        scanf("%d%d",&qua[i][0],&qua[i][1]);
        if(!qua[i][0]){
            add[++cntad]=i;
            b[++cntb]=qua[i][1];
            b[++cntb]=qua[i][1]+cntad;
        }
    }
    sort(b+1,b+cntb+1);
    cntb=unique(b+1,b+cntb+1)-(b+1);
    for(int i=1,k=0;i<=n;i++){
        if(qua[i][0])
            continue;
        ++k;
        int tmp=qua[i][1];
        qua[i][1]=lower_bound(b+1,b+cntb+1,tmp)-b;
        qua[i][2]=lower_bound(b+1,b+cntb+1,tmp+k)-b;
    }
}
int lowbit(int x){
    return x&(-x);
}
void Update(int *c,int x,int d)
{
    while(x<=cntb){
        c[x]+=d;
        x+=lowbit(x);
    }
}
int Getsum(int *c,int x)
{
    int ret=0;
    while(x){
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}
int main()
{
    int cas=0;
    while(scanf("%d",&n)==1){
        printf("Case #%d:\n",++cas);
        Init();
        read();
        for(int i=1;i<=n;i++){
            if(!qua[i][0]){
                printf("%d\n",(sum1-Getsum(c1,qua[i][1]-1))-(sum2-Getsum(c2,qua[i][2])));
                Update(c1,qua[i][1],1); sum1++;
                Update(c2,qua[i][2],1); sum2++;
            }
            else{
                int id=add[qua[i][1]];
                Update(c1,qua[id][1],-1); sum1--;
                Update(c2,qua[id][2],-1); sum2--;
            }
        }
    }
}

转载于:https://www.cnblogs.com/katarinayuan/p/6572814.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值