UVA - 11402 Ahoy, Pirates! (线段树)

In the ancient pirate ages, the Pirate Land was divided into two teams ofpirates, namely, the Buccaneer and the Barbary pirates.Each pirate’s team was not fixed, sometimes the opponent pirates attacked andhe was taken away to the other pirate team. All on
a sudden a magician appearedin the Pirate Land,where he was making transition of pirates from their team to other team at hisown will. Of course, handy spells were used. The process of changing team wasknown as mutating.

There were N pirates and all of the pirates have a unique idfrom 0 to N-1. The great magician could mutate a bunch of pirates withconsecutive id’s to another one.

Suppose there were 100 pirates in the pirate land and all ofthem were Barbary pirates, then the magician could casta spell to change pirates with id’s from 10 to 33 toBuccaneer pirates. Then the whole pirate land would have 24 Buccaneer and 76 Barbarypirates.

The magician was very fast casting the spell. Once, Godstarted to dislike this. God had favor for the Buccaneer pirates and God askedthe magician, “Tell me, how many of the pirates of index from 2 to 30 areBuccaneer pirates?”. Now the magician was puzzled
ashe was only efficient in casting spells, not in counting J

Being clever enough, the magician captured a clever man fromthe Earth Land.And unfortunately it’s you! Now you have to answer the God’s questions.

Input

The first line of input will contain number of test cases T.

For each test case:

The first part of the description will be of the pirateland. There could be up to N (1<=N<=1024000) pirates. Each pirate iseither assigned to Buccaneer or Barbary Pirate. Buccaneer pirates are describedby ‘1’ (ONE) and Barbary pirates are described by ‘0’(ZERO).
You have to build a string of the pirates’ description. Each casestarts with an integer M (M<=100), where M pair lines follow. In each pairof lines (we call it a set), first has an integer
(T<= 200) and next one has a nonempty string Pirates
(consisting of 0 and 1, 0 for Barbary,1 for Buccaneer, has maximum length of 50). For each pair concatenate thestring
Pirates, T times.Concatenate all the resulting M sets of strings to build the piratedescription. The final concatenated string describes the pirates from index 0to end (N-1 for N pirates).

Now the next part of the input will contain queries. Firstline of next part has an integer Q describing number of queries. Eachsubsequence Q (1<=Q<=1000) lines describe each query. Each query has astring F or E or I or S and two integers, a and bdenoting
indexes. The meaning of the query string arefollows:

F a b, means, mutate the pirates from index a to b to Buccaneer Pirates.

E a b, means, mutate the pirates from index a to b to Barbary Pirates.

I a b, means, mutate the pirates from index a to b to inverse pirates.

S a b, means, “God’s query” God is asking a question: “Tellme, how many Buccaneer pirates are there from index a tob?”

(a <= b, 0 <= a < n, 0<= b < n, index range are inclusive)

Output

For each test print the case number as the sample outputsuggests. Then for each of “God’s query”, output the query number, colon (:)and a space and the answer to the query as the sample suggest.

 

Sample Input                                                  Outputfor Sample Input


2

2

5

10

2

1000

5

F 0 17

I 0 5

S 1 10

E 4 9

S 2 10

3

3

1

4

0

2

0

2

I 0 2

S 0 8


Case 1:

Q1: 5

Q2: 1

Case 2:

Q1: 0

Explanation:

Case1:

The pirate land is as follows (N = 18)

101010101010001000

Before God’s first query it was as follows

000000111111111111

Case 2:

The pirate land is as follows (N=9)

111000000

题意:给你n个串,每个串重复若干次,再有就是三个操作:F a b 代表:将[a,b]的数变成1;E a b 代表:将区间[a,b]变成0;I a b 代表:取反;S a b 代表:计算[a,b]1的个数

思路:看了队友一个很巧妙的操作:0代表不变,1代表1,2代表2,3代表取反,其他的就是线段树的延迟标记了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson(x) ((x << 1) + 1)
#define rson(x) ((x << 1) + 2)
using namespace std;
const int maxn = 1024000;

struct Node {
	int l, r, num, flag;
	Node() {}
	Node(int l, int r) {
		this->l = l, this->r = r;
		num = flag = 0;
	}
	int len() {
		return r - l + 1;
	}
} node[maxn<<2];
int s[maxn];
char str[maxn];

void pushup(int pos) {
	node[pos].num = node[lson(pos)].num + node[rson(pos)].num;
}

void build(int pos, int l, int r) {
	node[pos] = Node(l, r);
	if (l == r) {
		node[pos].num = s[l];
		return;
	}
	int m = (node[pos].l + node[pos].r) >> 1;
	build(lson(pos), l, m);
	build(rson(pos), m+1, r);
	pushup(pos);
}

int getOp(int a, int b) {
	if (a == 3 && b == 3) return 0;
	if (a == 3 && b == 1) return 2;
	if (a == 3 && b == 2) return 1;
	if (a == 3 && b == 0) return 3;
	if (a == 2) return 2;
	if (a == 1) return 1;
	return 0;
}

void pushdown(int pos) {
	if (node[pos].flag) {
		int lo = getOp(node[pos].flag, node[lson(pos)].flag);
		node[lson(pos)].flag = lo;
		if (node[pos].flag == 2) node[lson(pos)].num = 0;
		if (node[pos].flag == 1) node[lson(pos)].num = node[lson(pos)].len();
		if (node[pos].flag == 3) node[lson(pos)].num = node[lson(pos)].len() - node[lson(pos)].num;

		int ro = getOp(node[pos].flag, node[rson(pos)].flag);
		node[rson(pos)].flag = ro;
		if (node[pos].flag == 2) node[rson(pos)].num = 0;
		if (node[pos].flag == 1) node[rson(pos)].num = node[rson(pos)].len();
		if (node[pos].flag == 3) node[rson(pos)].num = node[rson(pos)].len() - node[rson(pos)].num;
		node[pos].flag = 0;
	}
}

void update(int pos, int l, int r, int v) {
	if (node[pos].l >= l && node[pos].r <= r) {
		int ts = getOp(v, node[pos].flag);
		if (v == 1)
			node[pos].num = node[pos].len();
		else if (v == 2)
			node[pos].num = 0;
		else node[pos].num = node[pos].len() - node[pos].num;
		node[pos].flag = ts;
		return;
	}

	pushdown(pos);
	int m = (node[pos].l + node[pos].r) >> 1;
	if (l <= m)
		update(lson(pos), l, r, v);
	if (r > m)
		update(rson(pos), l, r, v);
	pushup(pos);
}

int query(int pos, int l, int r) {
	if (node[pos].l >= l && node[pos].r <= r)
		return node[pos].num;
	int ans = 0;
	pushdown(pos);
	int m = (node[pos].l + node[pos].r) >> 1;
	if (l <= m)
		ans += query(lson(pos), l, r);
	if (r > m)
		ans += query(rson(pos), l, r);
	pushup(pos);
	return ans;
}

int main() {
	int t, n, cnt, m, cas = 1;
	scanf("%d", &t);
	while (t--) {
		scanf("%d", &n);
		cnt = 0;
		while (n--) {
			scanf("%d", &m);
			scanf("%s", str);
			int len = strlen(str);
			while (m--) {
				for (int i = 0; i < len; i++)
					s[cnt++] = str[i] - '0';
			}
		}

		build(0, 0, cnt-1);
		int q;
		scanf("%d", &q);
		char que[5];
		int a, b, c;
		printf("Case %d:\n", cas++);
		int qn = 1;
		while (q--) {
			scanf("%s%d%d", que, &a, &b);
			if (que[0] == 'F') update(0, a, b, 1);
			if (que[0] == 'E') update(0, a, b, 2);
			if (que[0] == 'I') update(0, a, b, 3);
			if (que[0] == 'S') printf("Q%d: %d\n", qn++, query(0, a, b));
		}
	}
	return 0;
}
时间: 2024-12-11 20:30:49

UVA - 11402 Ahoy, Pirates! (线段树)的相关文章

UVA11402 - Ahoy, Pirates!(线段树)

题目链接 题目大意:给你n个01串,每个串拼接m次得到新串,最后在把这n个新串拼接起来得到最终的目标串. 然后给你四种操作: F a b :把位置a到b都置为1: E a b :把位置a到b都置为0: I a b :把位置a到b上的数字翻转(0,1互换): S a b :查询位置a到b有多少个1. 解题思路:线段树节点内部附加信息:setv:标记这个结点范围内有set值,并且需要传递到这个节点的孩子.resv:标记这个节点范围内有翻转,并且也需要传递到这个节点的孩子.注意:setv和resv标记

UVA 11983 - Weird Advertisement(线段树)

UVA 11983 - Weird Advertisement 题目链接 题意:给定几个矩形,之后,求覆盖k次以上的点 思路:先把坐标离散化掉,然后把每个矩形x2,y1加一,这样就把求点转化为求面积,然后每个矩形拆分成上下两个线段,按y排序之后,从下往上每访问一条线段(第一条除外),答案就加上目前整条线段上次数大于等于k的长度乘上这条线段和上一条线段的高度差,然后再用这条线段,根据它是矩形下面还是上面的线段去更新整条线段,维护线段大于等于k的长度这步利用线段树 代码: #include <cst

UVA 11983 Weird Advertisement 线段树+离散化+扫描线

有点像HDU 3642的强化版.给你N个矩形的坐标,问题平面上被k个不同的矩形覆盖的面积是多少. 当初HDU 3642 是直接一个一个手写的,这里的k虽然说只有10,合并过成一个一个手写也是相当蛋疼的,不过仔细想一下,不难推出一般性的关系,然后直接用循环搞就好了.不过我还是因为有个地方忘记初始化WA了2发,真是弱o(╯□╰)o 注意每个房子代表一个点,而我们要把他转化成线段,对坐标进行一些简单的变换即可. #include <cstdio> #include <cstring> #

UVA 11235 Frequent values 线段树/RMQ

vjudge 上题目链接:UVA 11235 *******************************************************大白书上解释************************************************************ 题目大意:给出一个非降序排列的整数数组 a1,a2,a3,...,an,你的任务是对于一系列询问 (i, j),回答 ai,ai+1,...,aj 中出现次数最多的值所出现的次数. 输入格式:包含多组数据.每组

uva 11983 - Weird Advertisement(线段树)

题目链接:uva 11983 - Weird Advertisement 题目大意:给定n个矩形,问说有多少区域的面积被覆盖k次以上. 解题思路:将每个矩形差分成两条线段,一段为添加覆盖值1,一段为减少覆盖值1,同时记录两段的高度(横坐标).然后对纵坐标离散化建立线段树,然后对线段按照高度排序,维护整段区间中覆盖度大于K的长度,乘上高度上的范围即可. #include <cstdio> #include <cstring> #include <vector> #incl

UVA 11983 Weird Advertisement --线段树求矩形问题

题意:给出n个矩形,求矩形中被覆盖K次以上的面积的和. 解法:整体与求矩形面积并差不多,不过在更新pushup改变len的时候,要有一层循环,来更新tree[rt].len[i],其中tree[rt].len[i]表示覆盖次数大于等于i的线段长度,以便求面积,最后只要每次都用tree[1].len[K]来算面积即可. 代码: #include <iostream> #include <cmath> #include <iostream> #include <cst

UVA 11525 Permutation ——(线段树,脑筋急转弯)

只要注意到对于譬如:S1*(k-1)! 因为后面k-1个数字的全排列个数刚好是(k-1)!,那么第一个数字就是没有取过的数字的第(S1+1)个即可.取走这个数字以后这个数字就不能再用了,依次类推即可得到整个排列了. 那么随便用线段树维护一下即可. 代码如下: 1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #define t_mid (l+r>>1) 5 #define

11402 - Ahoy, Pirates!(线段树区间更新(标记重叠的处理))

题目链接:点击打开链接 题意:有3种区间操作, 将某个区间全部变成1: 将某个区间全部变成0:将某个区间的1变成0, 0变成1. 思路:前两个操作就是最基本的区间更新, 用到懒惰标记, 然而第3个操作却有些麻烦, 如果仅仅更新当前这个结点对应的大区间, 那么它所包含的小区间再次更新时就会发生错误, 错误的原因是因为标记的重叠和碰撞.  显然 , 这就是很典型的一个问题, 处理标记碰撞的问题. 问题的核心是解决碰撞, 使得每个点每个时刻至多只有一个标记. 那么怎么办呢?我们可以在两个标记发生碰撞的

Uva 1232 - SKYLINE ( 线段树 + 区间更新 )

Uva 1232 SKYLINE (线段树 + 区间更新) 题意: 按照顺序在地面上建造放在,每个房子的高度为h,操作 l r h 表示 在(l,r] 区间建立一个高度为h的房子.统计每次建立完房子之后的overlap值之和 overlap值表示[ 修完一座房子之后,统计它在多长的部分是最高的(可以和其他房子并列高) ]如样例图,按照灰.黒.白的顺序建立房子 ans = (11-5) + (5-1) + (5-3) + (13-11) = 6 + 4 + 4 = 14 分析: 一开始一直想不明白