hdu5372 Segment Game (樹狀數組)

題意:每次插入一條線段或刪除之前一條線段,每次操作線段長度遞增,求插入一段線段時有多少線段被它完全覆蓋。

由於保證線段長度遞增,我們可以用右斷點在合法區間內的減去左端點不在合法區間的,可以用樹狀數組分開維護。

下標需要離散化。

下標可以是負數,這讀入優化坑了我一個小時。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<assert.h>
#include<algorithm>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define erp(i,a,b) for(int i=a;i>=b;--i)
#define clr(x) memset(x,0,sizeof x)
#define LL long long
const int inf = 0x3f3f3f3f;
const int MAXN = 700005;
int N;

void get(int&r)
{
	char c, f=0;r=0;
	do{ c=getchar();if(c=='-')f=1;} while(c<'0'||c>'9');
	do r=r*10+c-'0',c=getchar(); while(c>='0'&&c<='9');
	if (f) r=-r;
}

int c1[MAXN*2], c2[MAXN*2];
void add(int *c, int i, int x)
{
	for (; i<MAXN*2; i+=i&-i)
		c[i] += x;
}
int qsum(int*c, int i)
{
	int r = 0;
	for (; i>0; i-=i&-i)
		r += c[i];
	return r;
}

int b[MAXN], to[MAXN];
int d1[MAXN], d2[MAXN];
int dat[MAXN*2], dn;
int idx(int x) { return lower_bound(dat+1,dat+dn+1,x) - dat; }
int main()
{
	int cid = 0, len;
	while (~scanf("%d", &N))
	{
		memset(c1, 0, sizeof c1);
		memset(c2, 0, sizeof c2);
		len = dn = 0;
		rep(i, 1, N)
		{
			get(d1[i]), get(d2[i]);
			if (d1[i] == 0)
			{
				++len;
				dat[++dn] = d2[i];
				dat[++dn] = d2[i] + len;
			}
		}
		printf("Case #%d:\n", ++cid);
		len = 0;
		sort(dat+1, dat+dn+1);
		dn = unique(dat+1,dat+dn+1)-dat-1;
		rep(i, 1, N)
		{
			if (d1[i] == 0)
			{
				++len;
				to[len] = idx(d2[i] + len);
				b[len] = idx(d2[i]);
				assert(dat[to[len]] == d2[i]+len);
				assert(dat[b[len]] == d2[i]);
				printf("%d\n",  qsum(c2, to[len]) - qsum(c1, b[len]-1));
				add(c1, b[len], 1), add(c2, to[len], 1);
			}
			else
			{
				add(c1, b[d2[i]], -1);
				add(c2, to[d2[i]], -1);
			}
		}
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章