线段树区间染色,这个问题和一般的线段树有区别,更新和查询操作都需要注意。还要把数组开大一点。
参考(抄)了大佬的博客
poj2777
题意:涂颜色,有两种操作P和C,C :a,b,c三个数,表示把a,b区间内都涂成c这种颜色
P:a,b两个数,代表询问a,b区间内的颜色种类
#pragma warning(disable:4996)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
#include<algorithm>
#include<climits>
using namespace std;
typedef long long ll;
bool vis[35];
int ans;
struct node
{
int l, r, c;
};
node tree[300005 << 2];
//结构体数组开大一点
void build(int L, int R, int k)
{
tree[k].l = L; tree[k].r = R;
tree[k].c = 1;//最初的颜色都是1
if (L == R)return;
int mid = (L + R) / 2;
build(L, mid, 2 * k);
build(mid + 1, R, 2 * k + 1);
}
//建树
void update(int c, int L, int R, int k)
{
if (tree[k].l >= L && R >= tree[k].r)//找到区间,改变颜色
{
tree[k].c = c;
return;
}
if (tree[k].c)
{
tree[2 * k].c = tree[2 * k + 1].c = tree[k].c;
tree[k].c = 0;
}//下传操作
int mid = (tree[k].l + tree[k].r) / 2;
if (L <= mid) update(c, L, R, 2 * k);
if (R > mid)update(c, L, R, 2 * k + 1);//更新左右儿子区间
/*
if (R <= mid)update(c, L, R, 2 * k);//完全在左边
else if (L > mid)update(c, L, R, 2 * k + 1);//完全在右边
else
{
update(c, L, mid, 2 * k);
update(c, mid + 1, R, 2 * k + 1);
}*/
}
void query(int k, int L, int R)
{
if (tree[k].c)//区间没有其他颜色
{
if (!vis[tree[k].c])//没有被标记过
{
vis[tree[k].c] = 1;
ans++;
}
return;
}
int mid = (tree[k].l + tree[k].r) / 2;
if (R <= mid)query(2 * k, L, R);
else if (L > mid)query(2 * k + 1, L, R);
else
{
query(2 * k, L, mid);
query(2 * k + 1, mid + 1, R);
}
}
int main()
{
int n, C, m, i, j, t1, t2, t3;
char s[2];
while (scanf("%d%d%d", &n, &C, &m) == 3)
{
memset(tree, 0, sizeof(tree));
build(1, n, 1);
while (m--)
{
scanf("%s", s);
if (s[0] == 'C')
{
scanf("%d%d%d", &t1, &t2, &t3);
if (t1 > t2)
{
j = t1;
t1 = t2;
t2 = j;
}//处理t1>t2的情况
update(t3, t1, t2, 1);
}
else
{
scanf("%d%d", &t1, &t2);
ans = 0;
memset(vis, 0, sizeof(vis));
if (t1 > t2)
{
j = t1;
t1 = t2;
t2 = j;
}
query(1, t1, t2);
printf("%d\n", ans);
}
}
}
return 0;
}
poj2528
题意:贴海报,海报的长度在1到1e7范围内,最多有1万张海报,先贴的海报会被后贴的海报覆盖
问最后有多少张海报可以被看见,露出一部分就可以
#pragma warning(disable:4996)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
#include<algorithm>
#include<climits>
using namespace std;
typedef long long ll;
const int maxn = 20005;
int inl[maxn], inr[maxn],vis[maxn];
int a[maxn << 2],ans;
struct node
{
int l, r, c;
};
node tree[maxn << 4];
void build(int L, int R, int k)
{
tree[k].l = L;tree[k].r = R;
tree[k].c = 0;
if (L == R)return;
int mid = (L + R) / 2;
build(L, mid, 2 * k);
build(mid + 1, R, 2 * k + 1);
}
//建树
void update(int L, int R, int c, int k)
{
if (L == tree[k].l && R == tree[k].r)
{
tree[k].c = c;
return;
}
if (tree[k].c)
{
tree[2 * k].c = tree[k].c;
tree[2 * k + 1].c = tree[k].c;
tree[k].c = 0;
}
int mid = (tree[k].l + tree[k].r) / 2;
if (R <= mid)update(L, R, c, 2 * k);
else if (L > mid)update(L, R, c, 2 * k + 1);
else
{
update(L, mid, c, 2 * k);
update(mid + 1, R,c, 2 * k + 1);
}
}
//更新
void query(int L, int R, int k)
{
if (tree[k].c)
{
if (!vis[tree[k].c])
{
ans++;
vis[tree[k].c] = 1;
}
return;
}
if (tree[k].l == tree[k].r)return;
int mid = (tree[k].l + tree[k].r) / 2;
if (R <= mid)query(L, R, 2 * k);
else if (L > mid)query(L, R, 2 * k + 1);
else
{
query(L, mid, 2 * k);
query(mid + 1, R, 2 * k + 1);
}
}
int main()
{
int T, i, j, n,t;
scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
j = 0;
for (i = 1;i <= n;i++)
{
scanf("%d%d", &inl[i], &inr[i]);
a[j++] = inl[i];
a[j++] = inr[i];
}
//把左右区间的数值输入,a数组下标从0到j-1
sort(a, a + j);
j=unique(a, a + j) - a;
//先排序再去重
t = j;
for (i = 1;i < t;i++)
{
if (a[i] > (a[i - 1] + 1))
{
a[j++] = a[i - 1] + 1;
}
}
//当相邻两项的差值大于1的时候,需要在中间加一个数
//直接先加在数组的最后,然后再排序
sort(a, a + j);
memset(tree, 0, sizeof(tree));
memset(vis, 0, sizeof(vis));
//此时的j代表元素的个数,也是区间长度,线段树是从1开始的
//所以,build(1,j,1)
build(1, j, 1);
//cout << " J " << j << endl;
for (i = 1;i <= n;i++)
{
inl[i] = lower_bound(a, a + j, inl[i]) - a + 1;
inr[i] = lower_bound(a, a + j, inr[i]) - a + 1;
//cout << inl[i] << " " << inr[i] << endl;
update(inl[i], inr[i], i, 1);
}
ans = 0;
query(1, j, 1);
printf("%d\n", ans);
}
return 0;
}