主要考线段树的区间修改和区间查询,这里有一个问题就是这么把一个区间的多种颜色上传给父亲甚至祖先节点,在这里题目告诉我们最多30颜色,那么我们可以把这30中颜色用二进制储存和传给祖先节点,二进制的每一位有0和1两种情况,0表示这个区间不存在这种颜色,1就表示存在,我在这里用到或运算,我们确定一个非叶子节点的值时,可以把它的两个儿子节点的值做或运算,只要某一位有1,那么这一位就是1了,这样就完成了颜色的上传。看代码吧。
建树:
struct node{ int w,f; //w是颜色的二进制表示的值,f是懒标记 }tree[4*1000000+10]; int n,m,k,t,a,b,c,ans; void build(int l,int r,int k) { tree[k].f=0; if(l==r) { tree[k].w=(1<<1); //初始都是2,把二进制第二位变成1 return; } int mid=(l+r)/2; build(l,mid,k*2); build(mid+1,r,k*2+1); tree[k].w=tree[k*2].w|tree[k*2+1].w; }
区间修改:(区间是a到b,颜色是c)
void change_interval(int l,int r,int k) { if(l>=a&&r<=b) { tree[k].f=c; tree[k].w=(1<<(c-1)); return ; } if(tree[k].f) //下传懒标记 down(k); int mid=(l+r)/2; if(mid>=a) change_interval(l,mid,k*2); if(mid<b) change_interval(mid+1,r,k*2+1); tree[k].w=tree[k*2].w|tree[k*2+1].w; }
区间查询:我把所有颜色都保存到了ans里
void ask_interval(int l,int r,int k) { if(l>=a&&r<=b) { ans|=tree[k].w; return; } if(tree[k].f) down(k); int mid=(l+r)/2; if(a<=mid) ask_interval(l,mid,k*2); if(b>mid) ask_interval(mid+1,r,k*2+1); tree[k].w=tree[k*2].w|tree[k*2+1].w; }
完整代码:
#include<iostream> #include<cstring> using namespace std; struct node{ int w,f; }tree[4*1000000+10]; int n,m,k,t,a,b,c,ans; void build(int l,int r,int k) { tree[k].f=0; if(l==r) { tree[k].w=(1<<1); return; } int mid=(l+r)/2; build(l,mid,k*2); build(mid+1,r,k*2+1); tree[k].w=tree[k*2].w|tree[k*2+1].w; } void down(int k) { tree[k*2].f=tree[k].f; tree[k*2+1].f=tree[k].f; tree[k*2].w=1<<(tree[k].f-1); tree[k*2+1].w=1<<(tree[k].f-1); tree[k].f=0; } void change_interval(int l,int r,int k) { if(l>=a&&r<=b) { tree[k].f=c; tree[k].w=(1<<(c-1)); return ; } if(tree[k].f) down(k); int mid=(l+r)/2; if(mid>=a) change_interval(l,mid,k*2); if(mid<b) change_interval(mid+1,r,k*2+1); tree[k].w=tree[k*2].w|tree[k*2+1].w; } void ask_interval(int l,int r,int k) { if(l>=a&&r<=b) { ans|=tree[k].w; return; } if(tree[k].f) down(k); int mid=(l+r)/2; if(a<=mid) ask_interval(l,mid,k*2); if(b>mid) ask_interval(mid+1,r,k*2+1); tree[k].w=tree[k*2].w|tree[k*2+1].w; } int main() { while(cin>>n>>m) { if(!n&&!m) break; build(1,n,1); for(int i=0;i<m;i++) { char ch[3]; cin>>ch; if(ch[0]=='P') { cin>>a>>b>>c; change_interval(1,n,1); } else if(ch[0]=='Q') { cin>>a>>b; ans=0; ask_interval(1,n,1); int ss[35],cnt=0; //这个ss数组是为了保存颜色,好控制格式 memset(ss,0,sizeof(ss)); for(int i=1;i<=30;i++) { if(1&(ans>>(i-1))) ss[++cnt]=i; } for(int i=1;i<=cnt;i++) { if(i!=cnt) cout<<ss[i]<<' '; else cout<<ss[i]<<endl; } } } } return 0; }