您的位置:首页 > 其它

Poj 4047 Garden /2012金华邀请赛D题(线段树)

2012-05-09 22:08 465 查看
题意:给出长度为200000的数列,进行200000次下列操作:

0 x y 将x的值置为y

1 x y 交换x和y的值

2 x y 求[x,y]区间内和最大的一个连续的长度为k的区间(y-x>k)

解法:显而易见的线段树开始一直想维护每个区间的最大k区间,但是一直想不出怎么维护父节点和子节点的关系。估计如果实在现场会困死在此题。。。

于是需要转换一下思维,把点当做区间把区间当做一个点,具体来说,线段树上每个叶子节点i的值为数列i~i+k-1的和,这样求[x,y]的最大值就转换成了求[x,y-k+1]区间的最大值,对于每次对于点的更新,更新它能影响到的所有长为k的区间,即 [x - k + 1,x];这种思想经常用到,比如前几天碰到的一道alibaba校园赛费用流问题(hdu4106)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
public class Garden {
class SegTree {
class node {
int left, right;
int max, add;
int mid() {
return (left + right) >> 1;
}
}
node tree[]=new node[600010];
void init(int left, int right, int idx, int a[]) {
tree[idx] = new node();
tree[idx].left = left;
tree[idx].right = right;
if (left == right) {
tree[idx].max = a[left];
return;
}
int mid = tree[idx].mid();
init(left, mid, idx << 1, a);
init(mid + 1, right, (idx << 1) | 1, a);
tree[idx].max = Math.max(tree[idx << 1].max,
tree[(idx << 1) | 1].max);
}

void pushdown(int idx) {
if (tree[idx].add == 0)
return;
int k = tree[idx].add;
tree[idx].max += k;
tree[idx].add = 0;
if (tree[idx].left == tree[idx].right)
return;
tree[idx << 1].add += k;
tree[(idx << 1) | 1].add += k;
}

void update(int left, int right, int idx, int v) {
pushdown(idx);
if (left <= tree[idx].left && right >= tree[idx].right) {
tree[idx].add += v;
return;
}
int mid = tree[idx].mid();
if (left <= mid)
update(left, right, idx << 1, v);
if (right > mid)
update(left, right, (idx << 1)|1, v);
pushdown(idx<<1);
pushdown((idx<<1)|1);
tree[idx].max = Math.max(tree[idx << 1].max,
tree[(idx << 1)|1].max);
}

int query(int left, int right, int idx) {
pushdown(idx);
if (tree[idx].left == left && tree[idx].right == right) {
return tree[idx].max;
}
int mid = tree[idx].mid();
if (right <= mid)
return query(left, right, idx << 1);
else if (left > mid)
return query(left, right, (idx << 1) | 1);
else
return Math.max(query(left, mid, idx << 1),
query(mid + 1, right, (idx << 1) | 1));
}
}

SegTree st = new SegTree();
int sum[]=new int[200010], arr[]=new int[200010], p[]=new int[200010];
StreamTokenizer in = new StreamTokenizer(new BufferedReader(
new InputStreamReader(System.in)));

int next() throws IOException {
in.nextToken();
return (int) in.nval;
}

void run() throws IOException {
int cas = next();
while (cas-- > 0) {
int n = next();
int m = next();
int k = next();
for (int i = 1; i <= n; i++) {
p[i] = next();
sum[i] = p[i] + sum[i - 1];
}
for (int i = 1; i + k - 1 <= n; i++)
arr[i] = sum[i + k - 1] - sum[i - 1];
st.init(1, n - k + 1, 1, arr);
while (m-- > 0) {
int op =next();
int x = next();
int y = next();
if (op == 0) {
int from = x - k + 1;
if (from < 1)
from = 1;
int key = y - p[x];
p[x] = y;
st.update(from, x, 1, key);
}
if (op == 1) {
int from=x-k+1;
if(from<1)
from=1;
int temp=p[x];
int key=p[y]-p[x];
p[x]=p[y];
st.update(from, x, 1, key);
from=y-k+1;
if(from<1)
from=1;
key=temp-p[y];
p[y]=temp;
st.update(from, y, 1, key);
}
if(op==2)
{
int to=y-k+1;
System.out.println(st.query(x, to, 1));
}
}
}
}
public static void main(String[] args) throws IOException {
new Garden().run();
}
}


PS:再次感慨线段树的变化多端,虽然种过二三十颗树了还是驾驭不了,这几天继续种。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: