2016ユーティリティC Training for Data Structures B-卿先輩と基本法CDOJ 1325線分樹+離散化



B題:卿先輩と基本法
一節の区間をあげます.長さは1 e 8、Q回操作(Q<=1 e 5)、
操作には二つの種類があります.一つはある区間を染色すること、もう一つはある区間が染色されていない長さを調べることです.
 
離散化+線分樹は区間の染色を求めます.
えっと、離散化は簡単です.私のやり方はsort+unique+lowerです.boundは解決して、チャットの中で柱のおじいさんは突然1つ言って、実はuniqueはないことができて、思って、本当にえっと、番号を求めないで連続しなければならないならば、uniqueがないことができるので、しかし習慣があって、だから大丈夫です.
 
それから、線分樹は区間染色を求めます.これは01染色に相当するので、比較的簡単です.区間更新の時に、直接にこの区間のsumを修正して、lazyの賦値を1にします.下の分区間も全部染色されていますので、下のサブ区間のデータは全部使えなくなります.そして調べた時にlazyを下ろせばいいです.
 
もちろん、この問題は離散化による問題です.離散化後、一つの点は区間を表しています.そして、私の線分樹は閉区間になっていますので、統計に相当するのは点です.例えば、「1、4」の二つのサブ区間は「1、2」と「3、4」です.例えば、1,100,200,300,1,2,3,4に離散化すると、私の線分樹の中の[101,199]はこの区間でなくなってしまいますが、この区間の紛失は明らかに誤りをもたらす可能性があります.そして、私のやり方は各ノードの二つのサブ区間の中のこの部分の情報を表しています.そのサブゾーンの間では得られないので、対応する操作の中で対応する修正をすればいいです.
 
後に考えてみましたが、線分樹が左閉右開区間にあるなら、各点の前後に点を加えてから離散化すると、上のような問題が起こらないようです.感覚的には正しいようですが、深く考えていません.
コード:
#include 
#include 
#include 
#include 
using namespace std;
#define maxq 100005
#define lid (id<<1)
#define rid (id<<1|1)
int N, Q, num;
int data[maxq * 2];
int oper[maxq][3];
struct segtree
{
	int l, r;
	int sum, lazy;
	bool tag;
}tr[maxq * 8];
void discrete()
{
	sort(data + 1, data + 2 * Q + 1);
	num = unique(data + 1, data + 2 * Q + 1) - data;
	/*int t = num;
	for (int i = 2; i < t; ++i)
	{
		if (data[i] - data[i - 1] == 2)
			data[num++] = data[i] - 1;
		else if (data[i] - data[i - 1] >= 2)
		{
			data[num++] = data[i - 1] + 1;
			data[num++] = data[i] - 1;
		}
	}
	sort(data + 1, data + num);*/
	for (int i = 1; i <= Q; ++i)
	{
		oper[i][0] = lower_bound(data, data + num, oper[i][0]) - data;
		oper[i][1] = lower_bound(data, data + num, oper[i][1]) - data;
	}
}
void bulid(int id, int l, int r)
{
	tr[id].l = l; tr[id].r = r;
	if (l == r)
		return;
	int mid = (l + r) >> 1;
	bulid(lid, l, mid);
	bulid(rid, mid + 1, r);
}
void push_down(int id)
{
	if (tr[id].lazy != 0)
	{
		if (tr[id].l < tr[id].r)
		{
			tr[id].tag = 1;
			tr[lid].sum = (data[tr[lid].r] - data[tr[lid].l] + 1)*tr[id].lazy;
			tr[lid].lazy = tr[id].lazy;
			tr[rid].sum = (data[tr[rid].r] - data[tr[rid].l] + 1)*tr[id].lazy;
			tr[rid].lazy = tr[id].lazy;
		}
		tr[id].lazy = 0;
	}
}
void update(int id, int l, int r, int v)
{
	if (l == tr[id].l&&tr[id].r == r)
	{
		tr[id].sum = (data[tr[id].r] - data[tr[id].l] + 1)*v;
		tr[id].lazy = v;
		return;
	}
	push_down(id);
	int mid = (tr[id].l + tr[id].r) >> 1;
	if (r <= mid) update(lid, l, r, v);
	else if (l > mid) update(rid, l, r, v);
	else
	{
		tr[id].tag = 1;
		update(lid, l, mid, v);
		update(rid, mid + 1, r, v);
	}
	tr[id].sum = tr[lid].sum + tr[rid].sum + tr[id].tag*(data[tr[rid].l] - data[tr[lid].r] - 1);
}
int query(int id, int l, int r)
{
	if (l == tr[id].l&&r == tr[id].r)
	{
		return tr[id].sum;
	}
	push_down(id);
	int mid = (tr[id].l + tr[id].r) >> 1;
	if (r <= mid) return query(lid, l, r);
	else if (l > mid) return query(rid, l, r);
	else
	{
		return query(lid, l, mid) + query(rid, mid + 1, r) + tr[id].tag*(data[tr[rid].l] - data[tr[lid].r] - 1);
	}
}
int main()
{
	scanf("%d%d", &N, &Q);
	int a, b, c;
	for (int i = 1; i <= Q; ++i)
	{
		scanf("%d%d%d", &a, &b, &c);
		oper[i][0] = data[2 * i - 1] = b;
		oper[i][1] = data[2 * i] = c;
		oper[i][2] = a;
	}
	discrete();
	bulid(1, 1, num - 1);
	for (int i = 1; i <= Q; ++i)
	{
		if (oper[i][2] == 1)
			update(1, oper[i][0], oper[i][1], 1);
		else if (oper[i][2] == 2)
		{
			printf("%d
", data[oper[i][1]] - data[oper[i][0]] + 1 - query(1, oper[i][0], oper[i][1])); } } return 0; }