题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=610
解题思路:
这是第一次写题解写的
思路跟我之前写的POJ 2528差不多。
https://blog.csdn.net/weixin_43768644/article/details/89341259
区别是这题是要输出所有看得见的颜色,以及对应这种颜色有几段。
按顺序讲一下代码。
PART 1:
主函数中:找到建树的右界,以及初始化,build()将区间所有点染为8002
int MAXN = 1;
for (int i = 1;i<=n;i++){
scanf("%d %d %d",x+i,y+i,c+i);
x[i]++,c[i]++;
MAXN = max(MAXN,y[i]);
}
///init
build(1,1,MAXN);
//memset(tree,0,sizeof tree);
for (int i=0;i<=8000;i++) ans[i] = sum[i] = 0;
for (int i = 1;i<=n;i++){
if (x[i]<=y[i]) update(x[i],y[i],c[i],1,1,MAXN);
}
主函数外:
对于每次给出区间进行更新,初始都染色为8002
这样给出 2
1 3 1
6 8 1
这样的数据就没有问题了,之前我初始化为0应该就是一直wa在这个地方 。看一下我那个poj2528题解应该就能体会到了。 维护的是一段区间内存在的颜色,如果一段区间是一种颜色中间却断了很多段,按照之前的思路,统计出的答案会是1,显然错误。这里把初始化的无色当做一种颜色,就没问题了。
#define mid int m = l+r>>1
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define tl tree[rt<<1]
#define tr tree[rt<<1|1]
void push_up(int rt)
{
if (tl==-1||tr==-1) tree[rt] = -1;
else if (tl!=tr) tree[rt] = -1;
}
void update(int L,int R,int c,int rt,int l,int r)
{
if (L<=l && r<=R){
tree[rt] = c;
return ;
}
if (tree[rt] > 0) tl = tr = tree[rt];
mid;
if (L<=m) update(L,R,c,lson);
if (R>m) update(L,R,c,rson);
push_up(rt);
}
PART 2:
dfs遍历树得到答案,用了差分标记
void dfs(int rt,int l,int r)
{
if (tree[rt] > 0){
sum[l] += tree[rt];
sum[r+1] -= tree[rt];
return ;
}
if (tree[rt] == -1){
mid;
dfs(lson);
dfs(rson);
}
}
主函数中:
dfs(1,1,MAXN);
for (int i=2;i<=MAXN;i++) sum[i] += sum[i-1];
int pre = 0;
for (int i=1;i<=MAXN;i++){
if (sum[i]!=pre){
ans[sum[i]-1]++;
pre = sum[i];
}
}
完整代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#define mid int m = l+r>>1
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define tl tree[rt<<1]
#define tr tree[rt<<1|1]
using namespace std;
const int N = 8000+5;
int tree[N<<2],sum[N],ans[N];
int x[N],y[N],c[N];
void push_up(int rt)
{
if (tl==-1||tr==-1) tree[rt] = -1;
else if (tl!=tr) tree[rt] = -1;
}
void update(int L,int R,int c,int rt,int l,int r)
{
if (L<=l && r<=R){
tree[rt] = c;
return ;
}
if (tree[rt] > 0) tl = tr = tree[rt];
mid;
if (L<=m) update(L,R,c,lson);
if (R>m) update(L,R,c,rson);
push_up(rt);
}
void build(int rt,int l,int r)
{
if (l==r){
tree[rt] = 8002;
return ;
}
mid;
build(lson);
build(rson);
push_up(rt);
}
void dfs(int rt,int l,int r)
{
if (tree[rt] > 0){
sum[l] += tree[rt];
sum[r+1] -= tree[rt];
return ;
}
if (tree[rt] == -1){
mid;
dfs(lson);
dfs(rson);
}
}
int main()
{
int n;
while (~scanf("%d",&n)){
int MAXN = 1;
for (int i = 1;i<=n;i++){
scanf("%d %d %d",x+i,y+i,c+i);
x[i]++,c[i]++;
MAXN = max(MAXN,y[i]);
}
///init
build(1,1,MAXN);
//memset(tree,0,sizeof tree);
for (int i=0;i<=8000;i++) ans[i] = sum[i] = 0;
for (int i = 1;i<=n;i++){
if (x[i]<=y[i]) update(x[i],y[i],c[i],1,1,MAXN);
}
dfs(1,1,MAXN);
for (int i=2;i<=MAXN;i++) sum[i] += sum[i-1];
int pre = 0;
for (int i=1;i<=MAXN;i++){
if (sum[i]!=pre){
ans[sum[i]-1]++;
pre = sum[i];
}
}
for (int i=0;i<=8000;i++)
if (ans[i]) printf("%d %d\n",i,ans[i]);
printf("\n");
}
return 0;
}
第二次写:
解题思路:
区间染色覆盖的问题,同时注意0也是一种颜色,初始化的状态应该为“无颜色状态”,为了方便涂颜色,每种颜色加一,最后减一就好了。
区间颜色覆盖,最后一次询问标记每个块的颜色。
然后进行统计。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define mid int m=l+r>>1
#define tl tree[rt<<1]
#define tr tree[rt<<1|1]
using namespace std;
const int N = 8e3+5;
int tree[N<<2];
int col[N],ans[N];
void push_down(int rt)
{
tl = tr = tree[rt];
}
void push_up(int rt)
{
if (tl==tr) tree[rt] = tl;
else tree[rt] = -1;
}
void update(int L,int R,int x,int rt,int l,int r)
{
if (L<=l && r<=R){
tree[rt] = x;
return ;
}
if (tree[rt]>=0) push_down(rt);
mid;
if (L<=m) update(L,R,x,lson);
if (R>m) update(L,R,x,rson);
push_up(rt);
}
void query(int rt,int l,int r)
{
if (tree[rt]>=0){
for (int i=l;i<=r;i++) col[i] = tree[rt];
return ;
}
mid;
query(lson);
query(rson);
}
void init(int rt,int l,int r)
{
if (l==r){
tree[rt] = 0;
return ;
}
mid;
init(lson);
init(rson);
push_up(rt);
}
int main()
{
int t,n,q,x,y,v;
while (~scanf("%d",&n)){
init(1,1,8000);
memset(ans,0,sizeof ans);
while (n--){
scanf("%d %d %d",&x,&y,&v);
x++;v++;
update(x,y,v,1,1,8000);
}
query(1,1,8000);
for (int i=1;i<=8001;i++){
//printf("col[%d]=%d\n",i,col[i]);
if (col[i]!=col[i-1]) ans[col[i]]++;
}
for (int i=1;i<=8001;i++) if (ans[i]) printf("%d %d\n",i-1,ans[i]);
printf("\n");
}
return 0;
}