/* 一开始以为跟hdu1698一样的,而这个题目求的是颜色的种类, hdu1698求的区间的和,sb的以为题目求的是一样的 线段建树是写的有点熟起来的,可是主要的Update还是不会的 */ #include <iostream> #include <cstdio> #include <cstring> #define LL(x) ((x) << 1) #define RR(x) ((x) << 1 | 1) using namespace std; const int N = 100005; struct Seg_tree{ int l, r, val; int mid(){ return (l + r) >> 1; } }tree[N * 3]; bool hash[100]; inline void Build(int l, int r, int node){ tree[node].l = l; tree[node].r = r; tree[node].val = 1; if(l == r){ return ; } int mid = tree[node].mid(); Build(l, mid, LL(node)); Build(mid + 1, r, RR(node)); } inline void Update(int l, int r, int node, int val){ //tree[node].val = -1; if(tree[node].l == l && tree[node].r == r){ tree[node].val = val; // 表示这段区间的颜色是纯色的 return ; } if(tree[node].val != -1){ // -1表示颜色混合的 tree[LL(node)].val = tree[RR(node)].val = tree[node].val; // 父节点是纯色的,子节点一定纯色的 tree[node].val = -1; // 把父节点赋值为杂色 } int mid = tree[node].mid(); if(r <= mid){ Update(l ,r, LL(node), val); } else if(l > mid){ Update(l , r, RR(node), val); } else{ Update(l, mid, LL(node), val); Update(mid + 1, r, RR(node), val); } } inline void Question(int l, int r, int node){ if(tree[node].l <= l && r <= tree[node].r){ if(tree[node].val != -1){ // l 到 r 这段区间是纯色的,标记一下,便于统计 hash[tree[node].val] = true; return ; } } int mid = tree[node].mid(); if(r <= mid){ Question(l, r, LL(node)); } else if(l > mid){ Question(l, r, RR(node)); } else{ Question(l, mid, LL(node)); Question(mid + 1, r, RR(node)); } } inline void Swap(int &a, int &b){ if(b < a) { int temp = a; a = b; b = temp; } } int main(){ int L, T, O; while(scanf("%d %d %d", &L, &T, &O) != EOF ){ Build(1, L, 1); char str[2]; int a, b, c; while(O--){ scanf("%s", str); if(str[0] == 'C'){ scanf("%d %d %d", &a, &b, &c); Swap(a, b);// 注意a b的大小 Update(a, b, 1, c); } else{ scanf("%d %d", &a, &b); Swap(a, b); // 注意a b的大小 memset(hash, false, sizeof(hash)); // 每次询问都要初始化 Question(a, b, 1); int ans = 0; for(int i = 1; i <= T; i++) if(hash[i]) ans++; printf("%d/n", ans); } } } } /* 题目给出改变颜色和查询操作,对于这个用线段树做比较好。由于颜色比较少,可以用二进制来表示颜色。 即每中颜色所占用的数位不一样。这样就很容易的求得每种颜色中不同颜色了。例如1101就是3种颜色。 而对2种不同的颜色求或运算,就可以得到他们的颜色之和。1101|1010—>1111就4个颜色了。 线段树就是每个节点表示一段范围,父节点的范围比子节点表示的范围大。对于二叉线段树, 可以将父节点的范围2分给子节点。 父节点的颜色就是子节点颜色的或运算。 http://www.cnblogs.com/cherip/archive/2008/09/19/1293789.html */ #include <iostream> #include <cstdio> #include <cstring> #define LL(x) ((x) << 1) #define RR(x) ((x) << 1 | 1) using namespace std; const int N = 100005; struct Seg_tree{ int l, r, val; int mid(){ return (l + r) >> 1; } }tree[N * 10]; //bool hash[100]; inline bool odd(int n){ //判断这个颜色是否为单色 return (n & (n - 1)) == 0; } inline void Build(int l, int r, int node){ tree[node].l = l; tree[node].r = r; tree[node].val = 1; if(l == r){ return ; } //int mid = tree[node].mid(); // 上一个程序这么写是没有RE的 int mid = (r + l)/ 2; Build(l, mid, LL(node)); Build(mid + 1, r, RR(node)); } inline void Update(int l, int r, int node, int val){ if(l <= tree[node].l && tree[node].r <= r){//如果此节点表示的范围完全被包含,则整个被重新改变颜色 tree[node].val = val; return ; } if(tree[node].val == val) return ;//节点颜色不需要被改变 if(odd(tree[node].val)){//如果节点为单色,则在上一次改变中,子树没有被改变,这个重新赋值 tree[LL(node)].val = tree[RR(node)].val = tree[node].val; } int mid = tree[node].mid(); if(l <= mid) Update(l, r, LL(node), val);//如果左子树需要被改变 if(r > mid) Update(l, r, RR(node), val);//右子树被改变 tree[node].val = tree[LL(node)].val | tree[RR(node)].val;//父节点的颜色等于2个子树的或和 } inline void Question(int l ,int r, int node, int &cnt){ if(l <= tree[node].l && tree[node].r <= r){ cnt = cnt | tree[node].val; return ; } if(odd(tree[node].val)){ cnt = cnt | tree[node].val; return ; } int mid = tree[node].mid(); if(l <= mid) Question(l , r, LL(node), cnt); if(r > mid) Question(l, r, RR(node), cnt); } inline void Swap(int &a, int &b){ if(b < a) { int temp = a; a = b; b = temp; } } inline int Count(int n){ //计算颜色数量 int temp = 0; while(n > 0){ if(n & 1) temp++; n >>= 1; } return temp; } int main(){ int L, T, O; while(scanf("%d %d %d", &L, &T, &O) != EOF ){ Build(1, L, 1); Update(1, L, 1, 1); char str[2]; int a, b, c; while(O--){ scanf("%s", str); if(str[0] == 'C'){ scanf("%d %d %d", &a, &b, &c); Swap(a, b);// 注意a b的大小 Update(a, b, 1, 1<<(c - 1)); } else{ scanf("%d %d", &a, &b); Swap(a, b); // 注意a b的大小 // memset(hash, false, sizeof(hash)); // 每次询问都要初始化 int cnt = 0; Question(a, b, 1, cnt); int ans = Count(cnt); // for(int i = 1; i <= T; i++) // if(hash[i]) // ans++; printf("%d/n", ans); } } } }