您的位置:首页 > 其它

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

2016-02-19 21:08 309 查看
题目描述

表示看错题目的一小部分,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--;
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: