题目大意:多组数据,每组给一个n(1=<n<=8000),下面有n行,每行有l,r,color(1=<color<=8000),表示将l~r颜色变为color,最后求各种颜色(1~8000)所占区段数,如果所占区段为0则不用输出。
解题思路:基本还是跟区间染色问题差不多,但要注意一些东西
①这里l,r指的是端点。比如
3
1 4 1
1 2 2
3 4 3
这组数据最后输出结果为:
1 1
2 1
3 1
原因是还有[2,3]这一段颜色为1,处理办法是将更新函数写成(1,l+1,r,color)也就是左闭右开的形式,这样就可以使得中间的那块区间不背忽略。
②题目都没给总区间长度,所以无论查询还是建树,我们都默认用0~8000。
③关于查询各颜色所占区段数的问题,不可能直接通过线段树找到个颜色区段数,因为还要考虑两个子树是相邻的情况。所以可以通过使用一个vis[i]数组,记录各区间的颜色,最后只要简单处理一下就可以得到结果了。
1 #include<cstring> 2 #include<stdio.h> 3 #include<iostream> 4 #define LC(a) ((a<<1)) 5 #define RC(a) ((a<<1)+1) 6 #define MID(a,b) ((a+b)>>1) 7 using namespace std; 8 typedef long long ll; 9 const int N=8e3*4; 10 11 struct node{ 12 ll l,r; 13 ll color;//颜色为-2表示混合色 14 }tree[N]; 15 16 ll ans[N]; 17 ll vis[N]; 18 //下推 19 void pushdown(ll p){ 20 tree[RC(p)].color=tree[LC(p)].color=tree[p].color; 21 } 22 //上推 23 void pushup(ll p){ 24 tree[p].color=(tree[LC(p)].color==tree[RC(p)].color?tree[LC(p)].color:-2); 25 } 26 27 void build(ll p,ll l,ll r){ 28 tree[p].l=l; 29 tree[p].r=r; 30 tree[p].color=-1;//初始化颜色因题意而定 31 if(l==r){ 32 return; 33 } 34 build(LC(p),l,MID(l,r)); 35 build(RC(p),MID(l,r)+1,r); 36 } 37 38 void update(ll p,ll l,ll r,ll color){ 39 if(r<tree[p].l||l>tree[p].r) 40 return; 41 if(tree[p].color==color) 42 return; 43 if(l<=tree[p].l&&r>=tree[p].r){ 44 tree[p].color=color; 45 return; 46 } 47 //**释放lazy标记 48 if(tree[p].color!=-2){ 49 pushdown(p); 50 } 51 update(LC(p),l,r,color); 52 update(RC(p),l,r,color); 53 pushup(p); 54 } 55 56 void query(ll p,ll l,ll r){ 57 if(r<tree[p].l||l>tree[p].r) 58 return; 59 60 //纯色,不用再找下去 61 if(tree[p].color!=-2){ 62 //**使用vis数组记录区间颜色 63 for(int i=tree[p].l;i<=tree[p].r;i++){ 64 vis[i]=tree[p].color; 65 } 66 return; 67 } 68 query(LC(p),l,r); 69 query(RC(p),l,r); 70 } 71 72 int main(){ 73 ios::sync_with_stdio(false); 74 ll n; 75 //注意是从0~n 76 while(cin>>n){ 77 build(1,0,8000); 78 ll maxc=0; 79 for(int i=1;i<=n;i++){ 80 ll l,r,color; 81 cin>>l>>r>>color; 82 maxc=max(maxc,color); 83 update(1,l+1,r,color); 84 } 85 memset(ans,0,sizeof(ans)); 86 memset(vis,-1,sizeof(vis)); 87 query(1,1,8000); 88 //处理vis数组,统计各区段数 89 for(int i=1;i<=8000;i++){ 90 if(vis[i]!=vis[i-1]&&vis[i]!=-1) 91 ans[vis[i]]++; 92 } 93 for(int i=0;i<=maxc;i++){ 94 if(ans[i]) 95 cout<<i<<" "<<ans[i]<<endl; 96 } 97 cout<<endl; 98 } 99 }