颜料大乱斗【NOIP2016提高A组模拟7.15】
2016-07-16 15:28
465 查看
题目
样例输入:
2 2 4
C 1 1 2
P 1 2
C 2 2 2
P 1 2
样例输出:
2
1
数据范围:
剖解题目:
给一串初始值相同的数,每次操作将一段区间内的数修改成另一个数,中途穿插询问一段区间内数字的个数。思路:明显的区间修改询问,就是线段树咯。
解法:
1.注意到颜色的种数小于等于30种,我们可以在线段树里开三十个数组表示这段区间的数字情况,然后每次修改时暴力修改即可。当然这方法明显是时间复杂度较高,这次打这种方法的人都过了,呵(。・・)ノ2.还是注意到颜色种数只有30种,我们可以用一个二进制数表示颜色的有无情况,然后线段树里父亲节点就是两个儿子节点的位或值。然后判断颜色多少种就不用说了吧?(谁让位运算是神奇的东西)
代码(解法二):
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #define fo(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=1e5+2; int n,c,m,sum; struct cy{ int val,idx; }tree[maxn*4]; void maketree(int p,int l,int r) { if (l==r) tree[p].val=1; else { int mid=(l+r)>>1; maketree(p<<1,l,mid); maketree(p<<1|1,mid+1,r); tree[p].val=tree[p<<1].val|tree[p<<1|1].val; } } void pushdown(int x,int p) { tree[p<<1].val=x; tree[p<<1].idx=x; tree[p<<1|1].val=x; tree[p<<1|1].idx=x; tree[p].idx=0; } void turn(int p,int l,int r,int a,int b,int val) { if ((l==a)&&(r==b)){ tree[p].idx=val; tree[p].val=val; return; } if (tree[p].idx!=0) pushdown(tree[p].idx,p); int mid=(l+r)>>1; if (b<=mid) turn(p<<1,l,mid,a,b,val); else if (a>mid) turn(p<<1|1,mid+1,r,a,b,val); else { turn(p<<1,l,mid,a,mid,val); turn(p<<1|1,mid+1,r,mid+1,b,val); } tree[p].val=(tree[p<<1].val)|(tree[p<<1|1].val); } void find(int p,int l,int r,int a,int b) { if (l==a&&r==b){ sum=sum|tree[p].val; return; } if (tree[p].idx!=0) pushdown(tree[p].idx,p); int mid=(l+r)>>1; if (b<=mid) find(p<<1,l,mid,a,b); else if (a>mid) find(p<<1|1,mid+1,r,a,b); else { find(p<<1,l,mid,a,mid); find(p<<1|1,mid+1,r,mid+1,b); } } int getsum(int x) { int ans=0; while (x){ int p=x&1; ans+=p; x>>=1; } return ans; } int main() { //freopen("T4.in","r",stdin); scanf("%d%d%d",&n,&c,&m); maketree(1,1,n); fo(i,1,m){ char ch[2]; scanf("%s",&ch); if (ch[0]=='C') { int x,y,z; scanf("%d%d%d",&x,&y,&z); if (x>y) swap(x,y); turn(1,1,n,x,y,1<<(z-1)); } else{ int x,y; scanf("%d%d",&x,&y); if (x>y) swap(x,y); sum=0; find(1,1,n,x,y); printf("%d\n",getsum(sum)); } } //fclose(stdin); }
相关文章推荐
- 使用位运算实现网页中的过滤、筛选功能实例
- C#枚举中的位运算权限分配浅谈
- shell 基本计算、逻辑运算、位运算详解
- Java位运算和逻辑运算的区别实例
- 优秀程序员必须知道的20个位运算技巧
- 图文详解C语言位运算基础知识
- JavaScript使用位运算符判断奇数和偶数的方法
- java位运算加密示例
- c语言中用位运算实现加法技巧介绍
- 基础的十进制按位运算总结与在Python中的计算示例
- Java 位运算(移位、位与、或、异或、非)
- 位运算应用口诀和实例
- 【位运算】之 异或
- JavaScript 位运算笔记
- 想知道&&与&及||与|之间的区别吗?
- 想知道&&与&及||与|之间的区别吗?
- 不用if判断将字母进行大小写转换
- 位级运算的一点随笔
- 线段树题集
- 优秀程序员不得不知道的20个位运算技巧