线段树增强训练题 ZOJ1610 Count the Colors
线段树增强训练,啊啊啊,我还是太菜了
这道题调试起码4个小时,明明一道很简单的题目。。。。
题意也看了好久,与一开始还读错题意了,但是问题不大,在原来的代码上改改也可
题意:对一段长为8000的线段进行染色,颜色有8000种,每次对区间[l,r]进行染色,进行n次操作后,问你每一种颜色有几段。
很明显的区间修改和查询,不假思索就动起手来、
但是要注意对于 相同颜色的[1,2]和[3,4]区间属于两段。
我们将每个节点视为一个的区间,对线段树的节点进行染色,如果该节点下的子节点颜色不同就将该节点视为颜色不明确(我们用-1表示)
基本思路是这样,我们先上AC代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=8001;
int n,le[maxn],ri[maxn],c[maxn],ans[maxn],vis[maxn];
struct Node{
int col;
}tree[maxn<<2];
void build(int l,int r,int node){
if(l==r){
tree[node].col=-1;
return;
}
int mid=(l+r)>>1;
build(l,mid,node<<1);
build(mid+1,r,node<<1|1);
tree[node].col=-1;
}
void push_down(int node){
if(tree[node].col>=0){
tree[node<<1].col=tree[node].col;
tree[node<<1|1].col=tree[node].col;
}
return;
}
void change(int fl,int fr,int x,int l,int r,int node){
push_down(node);
if(fr<l || fl>r || tree[node].col==x)
return;
if(fl<=l && fr>=r){
tree[node].col=x;
return ;
}
int mid=(l+r)>>1;
change(fl,fr,x,l,mid,node<<1);
change(fl,fr,x,mid+1,r,node<<1|1);
if(tree[node<<1].col==tree[node<<1|1].col)
tree[node].col=tree[node<<1].col;
else
tree[node].col=-1;
}
void findx(int l,int r,int node){
if(tree[node].col>=0)
{
for(int i=l;i<=r;i++)
vis[i]=tree[node].col;
return;
}
if(l!=r){
int mid=(l+r)>>1;
findx(l,mid,node<<1);
findx(mid+1,r,node<<1|1);
}
}
int main(){
while (~scanf("%d",&n)){
int len=0,cc=0;
for(int i=1;i<=n;i++){
scanf("%d %d %d",&le[i],&ri[i],&c[i]);
len=max(ri[i],len);
cc=max(cc,c[i]);
}
build(1,len,1);
for(int i=1;i<=n;i++){
change(le[i]+1,ri[i],c[i],1,len,1);
}
fill(vis,vis+1+len,-1);
fill(ans,ans+1+cc,0);
findx(1,len,1);
for (int i = 1; i <=len; i++)
{
if(vis[i]!=vis[i-1] && vis[i]>=0)
ans[vis[i]]++;
}
for(int i=0;i<=cc;i++){
if(ans[i])
printf("%d %d\n",i,ans[i]);
}
cout<<endl;
}
return 0;
}
说实话,这个代码我是从其他blog上Copy的思想,我原来的代码是WA的,感觉很不爽,但是我又查不出错,我把它放在最下面,希望有大佬能帮我指正!
WA的代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=8001;
int n,le[maxn],ri[maxn],c[maxn],ans,p;
struct Node{
int col;
}tree[maxn<<2];
void build(int l,int r,int node){
if(l==r){
tree[node].col=-1;
return;
}
int mid=(l+r)>>1;
build(l,mid,node<<1);
build(mid+1,r,node<<1|1);
tree[node].col=-1;
}
void push_down(int node){
if(tree[node].col>=0){
tree[node<<1].col=tree[node].col;
tree[node<<1|1].col=tree[node].col;
}
return;
}
void change(int fl,int fr,int x,int l,int r,int node){
push_down(node);
if(fr<l || fl>r || tree[node].col==x)
return;
if(fl<=l && fr>=r){
tree[node].col=x;
return ;
}
int mid=(l+r)>>1;
change(fl,fr,x,l,mid,node<<1);
change(fl,fr,x,mid+1,r,node<<1|1);
if(tree[node<<1].col==tree[node<<1|1].col)
tree[node].col=tree[node<<1].col;
else
tree[node].col=-1;
}
void findx(int l,int r,int node,int aim){
push_down(node);
if(tree[node].col<0){
int mid=(l+r)>>1;
if(l==r)
return;
findx(l,mid,node<<1,aim);
findx(mid+1,r,node<<1|1,aim);
if(tree[node<<1].col==tree[node<<1|1].col)
tree[node].col=tree[node<<1].col;
else
tree[node].col=-1;
}
else if(tree[node].col==aim){
if(!p)
ans++;
p=1;
return;
}
else{
p=0;
return;
}
}
int main(){
while (~scanf("%d",&n)){
int len=0;
for(int i=1;i<=n;i++){
scanf("%d %d %d",&le[i],&ri[i],&c[i]);
len=max(ri[i],len);
}
build(1,len,1);
for(int i=1;i<=n;i++){
change(le[i]+1,ri[i],c[i],1,len,1);
}
for(int i=0;i<8000;i++){
ans=0,p=0;
findx(1,len,1,i);
if(ans)
printf("%d %d\n",i,ans);
}
cout<<endl;
}
return 0;
}
和上面的AC代码相比,这个代码就只是改了答案的模式,我觉得利用线段树都是从左扫到右的特点,我对每个颜色进行遍历,ans记录答案,p代表上一个节点是否找到对应的颜色,如果当前节点对应p=1,上个节点不对应,则ans++,反之p=0,ans不变;
我的思路是这样的,但是不知道为什么会WA。。。QAQ
求大佬请教!!!!