解题报告 之 HDU5316 Magician

来源:互联网 发布:刺客信条3低配优化 编辑:程序博客网 时间:2024/04/29 15:49

解题报告 之 HDU5316 Magician


Description

Fantasy magicians usually gain their ability through one of three usual methods: possessing it as an innate talent, gaining it through study and practice, or receiving it from another being, often a god, spirit, or demon of some sort. Some wizards are depicted as having a special gift which sets them apart from the vast majority of characters in fantasy worlds who are unable to learn magic. 

Magicians, sorcerers, wizards, magi, and practitioners of magic by other titles have appeared in myths, folktales, and literature throughout recorded history, with fantasy works drawing from this background. 

In medieval chivalric romance, the wizard often appears as a wise old man and acts as a mentor, with Merlin from the King Arthur stories representing a prime example. Other magicians can appear as villains, hostile to the hero. 


Mr. Zstu is a magician, he has many elves like dobby, each of which has a magic power (maybe negative). One day, Mr. Zstu want to test his ability of doing some magic. He made the elves stand in a straight line, from position 1 to position n, and he used two kinds of magic, Change magic and Query Magic, the first is to change an elf’s power, the second is get the maximum sum of beautiful subsequence of a given interval. A beautiful subsequence is a subsequence that all the adjacent pairs of elves in the sequence have a different parity of position. Can you do the same thing as Mr. Zstu ? 

 

Input

The first line is an integer T represent the number of test cases. 
Each of the test case begins with two integers n, m represent the number of elves and the number of time that Mr. Zstu used his magic. 
(n,m <= 100000) 
The next line has n integers represent elves’ magic power, magic power is between -1000000000 and 1000000000. 
Followed m lines, each line has three integers like 
type a b describe a magic. 
If type equals 0, you should output the maximum sum of beautiful subsequence of interval [a,b].(1 <= a <= b <= n) 
If type equals 1, you should change the magic power of the elf at position a to b.(1 <= a <= n, 1 <= b <= 1e9) 
 

Output

For each 0 type query, output the corresponding answer.
 

Sample Input

11 110 1 1
 

Sample Output

1
 

题目大意:给出一个n个数字的序列,有两种操作。第一种操作是将某位置的数字改变为新的数字,第二种操作是问某范围内美丽子序列的最大和。所谓美丽子序列,就是指按顺序选出一些数,这些数中任意相邻的两个数的原位置编号必须一奇一偶。

分析:首先吐槽一下没有用的三段阅读理解以及一张诡异的图片。作为资深小白,看到这种各种操作的就只会想到线段树(毕竟数据结构不是我负责,囧)。那么问题的核心就在于节点要维护什么信息,经过思考之后一开始认为可以直接维护该区间的美丽子序列最大和,但是发现并不行,因为可能两个节点加在一起会出现与原来不同的美丽子序列(比如节点 i 的最大美丽子序列是 奇偶奇偶奇偶奇 ,j 的最大美丽子序列是奇偶奇偶奇偶,但这两个美丽子序列并不能直接相连。 可能 i 和 j 合并以后有更大的美丽子序列 奇偶奇偶奇偶奇偶奇偶奇偶)。

针对上面的问题,我们需要维护四个信息,就是以 奇/偶 开头 以 奇/偶 结尾的最大美丽子序列的和。然后剩下的工作就是裸的线段树了。

上代码:
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>typedef long long ll;using namespace std;struct Node{int ex[2][2];//exist 表示是否该区间是否存在以 奇/偶 开头/结尾的最大美丽子序列ll M[2][2]; //0表示奇,1表示偶数,M[0][1]表示该区间内以奇开头,以偶结尾的最大美丽子序列和}node[100000 * 4];Node conj( Node a, Node b ){Node c;for(int i = 0; i <= 1; i++)for(int j = 0; j <= 1; j++) //首先合并之后的区间可以直接以a、b区间的最大和作为最大和{c.ex[i][j] = a.ex[i][j] | b.ex[i][j];if(a.ex[i][j] && b.ex[i][j])c.M[i][j] = max( a.M[i][j], b.M[i][j] );else if(a.ex[i][j])c.M[i][j] = a.M[i][j];else if(b.ex[i][j])c.M[i][j] = b.M[i][j];}for(int i = 0; i <= 1; i++) //当然也有可能将两个区间的某个子序列合并起来for(int j = 0; j <= 1; j++)for(int k = 0; k <= 1; k++)if(a.ex[i][j] && b.ex[!j][k])if(c.ex[i][k])c.M[i][k] = max( c.M[i][k], a.M[i][j] + b.M[!j][k] );elsec.ex[i][k] = 1, c.M[i][k] = a.M[i][j] + b.M[!j][k];return c;}void build( int root, int l, int r ){memset( node[root].ex, 0, sizeof( node[root].ex ) );if(l == r){int a;scanf( "%d", &a );node[root].ex[l % 2][l % 2] = 1;node[root].M[l % 2][l % 2] = a;return;}int mid = (l + r) / 2;build( root * 2, l, mid );build( root * 2 + 1, mid + 1, r );node[root] = conj( node[root * 2], node[root * 2 + 1] );}void update( int root, int l, int r, int x, int y ){if(l == r){memset( node[root].ex, 0, sizeof( node[root].ex ) );node[root].ex[l % 2][l % 2] = 1;node[root].M[l % 2][l % 2] = y;return;}int mid = (l + r) / 2;if(x <= mid)update( root * 2, l, mid, x, y );elseupdate( root * 2 + 1, mid + 1, r, x, y );node[root] = conj( node[root * 2], node[root * 2 + 1] ); //更新完成后一路上的节点都要重新连接一下}Node query( int root, int l, int r, int x, int y )//找到并制作成要求的区间再返回{if(x <= l&&y >= r)return node[root];int flag1 = 0, flag2 = 0;Node x1, x2;int mid = (l + r) / 2;if(x <= mid)x1 = query( root * 2, l, mid, x, y ), flag1 = 1;if(y>mid)x2 = query( root * 2 + 1, mid + 1, r, x, y ), flag2 = 1;if(flag1 == 0)return x2;if(flag2 == 0)return x1;return conj( x1, x2 );}int main(){int T;cin >> T;while(T--){int n, m;cin >> n >> m;build( 1, 1, n );for(int i = 1; i <= m; i++){int x, y, z;scanf( "%d%d%d", &x, &y, &z );if(x == 0){Node t = query( 1, 1, n, y, z );ll ans;int flag = 0;for(int i = 0; i <= 1; i++)for(int j = 0; j <= 1; j++)if(t.ex[i][j])if(flag == 0)ans = t.M[i][j], flag = 1;elseans = max( ans, t.M[i][j] );cout << ans << endl;}elseupdate( 1, 1, n, y, z );}}return 0;}


0 0
原创粉丝点击