标签:
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 41202 | Accepted: 12458 |
Description
Input
Output
Sample Input
2 2 4 C 1 1 2 P 1 2 C 2 2 2 P 1 2
Sample Output
2 1
题目意思:给三个数n,t,m n代表区间大小,t代表颜色的种类(没什么用) m代表询问次数 操作为‘C‘时代表更新区间值,操作为‘Q‘时代表询问区间内的颜色数目并输出。
运用了lazy思想和位运算 。。看了别人的思想打出来的代码。。对理解线段树真的十分有用
lazy:只要插入的区间完全覆盖了当前结点所管理的区间就不再往下做了,在当前结点上打上一个lazy标记,然后直接返回。
下次如果遇到当前结点有lazy标记的话,直接传递给两个儿子,自己的标记清空。好处就是满足条件时就不用更新到子节点,节约时间。
位运算:用二进制来表示每一位的颜色(能够想出来的人真的要对算法非常了解,,,渣渣膜拜)比如说左边叶子节点被染成了3,右边的被染成了4
则 父亲节点就被两种颜色染过了 00...0100 | 00...1000 = 00...1100 代表此区间被 3和4所染过了 ,这题颜色最多30种,所以能够用 int表示
更多解释下面见代码:
#include<stdio.h> #include<algorithm> #include<string.h> #include<iostream> #define N 1100005 using namespace std; const int MAXSIZE = 100005; int sum; struct Tree{ int color; ///用二进制表示30种颜色,所以求每两个子区间的位或的结果就是父亲结点 int cover ;///表示某区间的颜色是否相同 int l,r; }tree[MAXSIZE<<2]; void pushUp(int i){ tree[i].color = tree[i<<1].color|tree[i<<1|1].color; } void pushDown(int i){ if(tree[i].cover==1){ tree[i<<1].color = tree[i].color; tree[i<<1|1].color = tree[i].color; tree[i<<1].cover = tree[i<<1|1].cover = 1; tree[i].cover = 0; } } void build(int l,int r,int idx){ tree[idx].l = l; tree[idx].r = r; tree[idx].color = 1; ///刚开始颜色都为1 tree[idx].cover = 1; ///刚开始区间颜色都是相同的 if(l==r) return ; int mid = (l+r)>>1; build(l,mid,idx<<1); build(mid+1,r,idx<<1|1); pushUp(idx); } void update(int l,int r,int idx,int val){ if(tree[idx].l>=l&&r>=tree[idx].r){ tree[idx].cover = 1; tree[idx].color=val; return; } pushDown(idx); int mid = (tree[idx].l+tree[idx].r)>>1; if(r<=mid) update(l,r,idx<<1,val); else if(l>mid) update(l,r,idx<<1|1,val); else { update(l,mid,idx<<1,val); update(mid+1,r,idx<<1|1,val); } pushUp(idx); } void query(int l,int r,int idx){ if(tree[idx].l>=l&&tree[idx].r<=r){ //printf("tree[%d].color = %d\n",idx,tree[idx].color); sum|=tree[idx].color; return; } if(tree[idx].cover==1){ ///该区间的颜色相同不需要往下分了 sum|=tree[idx].color; return; } int mid = (tree[idx].l+tree[idx].r)>>1; if(r<=mid) query(l,r,idx<<1); else if(l>mid) query(l,r,idx<<1|1); else { query(l,mid,idx<<1); query(mid+1,r,idx<<1|1); } } int solve(){ int ans = 0; //printf("sum = %d\n",sum); while(sum){ if(sum&1) ///如果sum的最低位是1则证明已经被染色 ans++; sum = sum>>1; } return ans; } int main() { int n,t,m; while(scanf("%d%d%d",&n,&t,&m)!=EOF){ build(1,n,1); while(m--){ char s[5]; scanf("%s",s); if(s[0]==‘C‘){ int a,b,c; scanf("%d%d%d",&a,&b,&c); update(a,b,1,1<<(c-1)); ///以二进制来表示颜色,比如染色成2 则二进制为00..010 即 2^1(^代表次方) }else{ int a,b; sum = 0; scanf("%d%d",&a,&b); query(a,b,1); printf("%d\n",solve()); } } } return 0; }
标签:
原文地址:http://www.cnblogs.com/liyinggang/p/5304085.html