tyvj 1297:
比较简单的线段树。
#include <stdio.h>
int a[50010];
struct node
{
int l, r, min, max;
};
node tree[50010 * 3];
void build(int ll, int rr, int s)
{
tree[s].l = ll;
tree[s].r = rr;
while(ll == rr)
{
tree[s].min = tree[s].max = a[ll];
return ;
}
int mid = (ll + rr) / 2;
build(ll, mid, s * 2);
build(mid + 1, rr, s * 2 + 1);
tree[s].min = tree[s * 2].min < tree[s * 2 + 1].min ? tree[s * 2].min : tree[s * 2 + 1].min;
tree[s].max = tree[s * 2].max > tree[s * 2 + 1].max ? tree[s * 2].max : tree[s * 2 + 1].max;
}
int search1(int ll, int rr, int s)
{
if(tree[s].l == ll && tree[s].r == rr)
return tree[s].max;
if(ll >= tree[s * 2 + 1].l)
return search1(ll, rr, s * 2 + 1);
if(rr <= tree[s * 2].r)
return search1(ll, rr, s * 2);
int mid = (tree[s].l + tree[s].r) / 2;
int t1 = search1(ll, mid, s * 2);
int t2 = search1(mid + 1, rr, s * 2 + 1);
return t1 > t2 ? t1 : t2;
}
int search2(int ll, int rr, int s)
{
if(tree[s].l == ll && tree[s].r == rr)
return tree[s].min;
if(ll >= tree[s * 2 + 1].l)
return search2(ll, rr, s * 2 + 1);
if(rr <= tree[s * 2].r)
return search2(ll, rr, s * 2);
int mid = (tree[s].l + tree[s].r) / 2;
int t1 = search2(ll, mid, s * 2);
int t2 = search2(mid + 1, rr, s * 2 + 1);
return t1 < t2 ? t1 : t2;
}
int main (void)
{
int n, p;
while(scanf("%d %d", &n, &p) != EOF)
{
int i;
for(i = 1; i <= n; i++)
scanf("%d", &a[i]);
build(1, n, 1);
//for(i = 1; i <= n * 2; i++)
// printf("l = %d, r = %d, min = %d, max = %d\n", tree[i].l, tree[i].r, tree[i].min, tree[i].max);
while(p --)
{
int x, y;
scanf("%d %d", &x, &y);
printf("%d ", search1(x, y, 1));
printf("%d\n", search2(x, y, 1));
}
}
return 0;
}
tyvj 1491:
这题开始我是用位运算做的,但是怎么都过不了最后一组数据。
原因就是如果给的修改区间很长的话,用for循环一个个改也还是很耗时。
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
int a[100010];
int main (void)
{
int n, p, k = 0;
scanf("%d %d", &n, &p);
int x, y, z, i;
while(p --)
{
scanf("%d", &x);
if(x & 1)
{
scanf("%d %d", &y, &z);
for(i = y; i <= z; i++)
a[i] ^= 1;
}
else
{
scanf("%d", &y);
printf("%d\n", a[y]);
}
}
return 0;
}
然后运用了线段树,感觉学长说的挺有道理的,线段树可以很灵活的使用,主要要看你怎么运用。(ps:写线段树特别容易出错好烦恼)
这题的线段树,结构体中存放一个标志f,表示这个区间是否有被改过,修改的时候只要修改区间正好是线段树中某个结点所表示的区间时,将结点中的f更改,就可以返回,不用再递归到最底层。但是因为这道题查抄的是某一个位置元素的值(不是某个区间),所以查找的时候,函数会递归到具体的那个元素上,然后再返回,在返回的过程中,只要所经过的结点的f是1,那么就将返回值改变,0改1,1改0,我是用全局变量实现的。
这题虽然查找的时候要递归到树的最底层,但是修改的时候挺省事的,特别是修改区间特别长的时候。
#include <stdio.h>
struct node
{
int l, r;
int f;
};
node tree[100010 * 3];
int val;
void build(int ll, int rr, int s)
{
tree[s].l = ll;
tree[s].r = rr;
tree[s].f = 0;
while(ll == rr)
return ;
int mid = (ll + rr) / 2;
build(ll, mid, s * 2);
build(mid + 1, rr, s * 2 + 1);
}
void modify(int ll, int rr, int s)
{
if(tree[s].l == ll && tree[s].r == rr)
{
tree[s].f ^= 1;
return;
}
if(ll >= tree[s * 2 + 1].l)
return modify(ll, rr, s * 2 + 1);//注意return = =
if(rr <= tree[s * 2].r)
return modify(ll, rr, s * 2);
int mid = (tree[s].l + tree[s].r) / 2;
modify(ll, mid, s * 2);
modify(mid + 1, rr, s * 2 + 1);
}
void search(int x, int s)
{
if(tree[s].l == x && tree[s].r == x)
{
if(tree[s].f)
val ^= 1;//如果f是1,那么就改变val的值
return;
}
int mid = (tree[s].l + tree[s].r) / 2;
if(x <= mid)
search(x, s * 2);
if(x > mid)
search(x, s * 2 + 1);
if(tree[s].f)
val ^= 1;//改变
}
int main (void)
{
int n, p, k;
while(scanf("%d %d", &n, &p) != EOF)
{
int i;
build(1, n, 1);
int k, x, y;
while(p --)
{
scanf("%d", &k);
if(k == 1)
{
scanf("%d %d", &x, &y);
modify(x, y, 1);
}
else
{
scanf("%d", &x);
val = 0;//最初元素的值都是1
search(x, 1);
printf("%d\n", val);
}
}
}
return 0;
}