您的位置:首页 > 其它

[kuangbin带你飞]专题七 线段树 【A、B、C、E、G、H】

2017-04-18 12:48 405 查看

题目链接:点击打开链接

A - 敌兵布阵

HDU - 1166                    

单点更新及区间求和。

更新时是在原有的基础上进行加减,直接进行加减即可。

AC代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX = 50010;
long long ans;
struct node
{
int l, r;
int sum;
} tree[MAX<<2];

void pushup(int rt)
{
tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}

void build(int l, int r, int rt)
{
tree[rt].l = l;
tree[rt].r = r;
tree[rt].sum = 0;
if(l == r) //叶子结点
{
scanf("%d",&tree[rt].sum);
return ;
}
int mid = (l+r)>>1;
//递归建树
build(l, mid, rt<<1);
build(mid+1, r, rt<<1|1);
pushup(rt);
}

void update(int pos, int val, int rt)
{
//更新这个区间的值
if(tree[rt].l == tree[rt].r)
{
tree[rt].sum += val;
return ;
}
int mid = (tree[rt].l+tree[rt].r)>>1;
if(pos <= mid)
update(pos, val, rt<<1);
else
update(pos, val, rt<<1|1);
pushup(rt);
}

void query(int x, int y, int rt)
{
if(x == tree[rt].l && y == tree[rt].r)
{
ans += tree[rt].sum;
return ;
}
int mid = (tree[rt].l+tree[rt].r)>>1;
if(y <= mid)
query(x, y, rt<<1);
else if(x > mid)
query(x, y, rt<<1|1);
else
{
query(x, mid, rt<<1);
query(mid+1, y, rt<<1|1);
}
}
int main()
{
int T;
int n, pos, val;
string s;
scanf("%d",&T);
for(int cas = 1; cas <= T; ++cas)
{
printf("Case %d:\n",cas);
scanf("%d",&n);
build(1, n, 1);
while(cin >> s)
{
if(s == "End") break;
scanf("%d%d",&pos,&val);
if(s == "Add")
{
update(pos, val, 1);
}
else if(s == "Sub")
{
update(pos, -val, 1);
}
else if(s == "Query")
{
ans = 0;
int x = pos;
int y = val;
if(x > y) swap(x, y);
query(x, y, 1);
cout << ans << endl;
}
}
}
return 0;
}


B - I Hate It

HDU - 1754                    

单点更新及区间最大值。

与A题不同的是,这里的单点更新是直接对数值进行替换,所以直接赋值即可。

AC代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX = 200010;
int ans;
struct node
{
int l, r;
int Max;
} tree[MAX<<2];

void pushup(int rt)
{
tree[rt].Max = max(tree[rt<<1].Max, tree[rt<<1|1].Max);
}

void build(int l, int r, int rt)
{
tree[rt].l = l;
tree[rt].r = r;
if(l == r) //叶子结点
{
scanf("%d",&tree[rt].Max);
return ;
}
int mid = (l+r)>>1;
//递归建树
e43f

build(l, mid, rt<<1);
build(mid+1, r, rt<<1|1);
pushup(rt);
}

void update(int pos, int val, int rt)
{
//更新这个区间的值
if(tree[rt].l == tree[rt].r)
{
tree[rt].Max = val;
return ;
}
int mid = (tree[rt].l+tree[rt].r)>>1;
if(pos <= mid)
update(pos, val, rt<<1);
else
update(pos, val, rt<<1|1);
pushup(rt);
}

void query(int x, int y, int rt)
{
if(tree[rt].l == x && tree[rt].r == y)
{
ans = max(ans, tree[rt].Max);
return ;
}
int mid = (tree[rt].l+tree[rt].r)>>1;
if(y <= mid)
query(x, y, rt<<1);
else if(x > mid)
query(x, y, rt<<1|1);
else
{
query(x, mid, rt<<1);
query(mid+1, y, rt<<1|1);
}
}
int main()
{
int n, m;
int x, y;
string q;
while(~scanf("%d%d",&n,&m))
{
build(1, n, 1);
while(m--)
{
cin >> q >> x >> y;
if(q == "Q")
{
ans = 0;
query(x, y, 1);
cout << ans << endl;
}
else
update(x, y, 1);
}
}
return 0;
}


C - A Simple Problem with Integers

POJ - 3468                    

区间更新及区间求和。

因为区间更新后的值不一定会一下子用到,所以进行延迟操作,通过lazy标记实现。

AC代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX = 100010;
struct node
{
int l, r;
long long sum, lazy;
} tree[MAX<<2];

void pushup(int rt)
{
tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}

void pushdown(int rt) //延迟操作,更新当前结点的叶子
{
int len = tree[rt].r - tree[rt].l + 1;
tree[rt<<1].sum += tree[rt].lazy*(len-len/2);
tree[rt<<1|1].sum += tree[rt].lazy*(len/2);
tree[rt<<1].lazy += tree[rt].lazy;
tree[rt<<1|1].lazy += tree[rt].lazy;
tree[rt].lazy = 0;
}

void build(int l, int r, int rt)
{
tree[rt].l = l;
tree[rt].r = r;
tree[rt].sum = tree[rt].lazy = 0;
if(l == r)
{
scanf("%lld",&tree[rt].sum);
return ;
}
int mid = (l+r)>>1;
//递归建树
build(l, mid, rt<<1);
build(mid+1, r, rt<<1|1);
pushup(rt);
}

void update(int x, int y, long long val, int rt)
{
//更新这个区间的值
if(tree[rt].l == x && tree[rt].r == y)
{
tree[rt].lazy += val;
tree[rt].sum += (y-x+1)*val;
return ;
}
if(tree[rt].lazy)
pushdown(rt);  //向下更新枝叶的值
int mid = (tree[rt].l+tree[rt].r)>>1;
if(y <= mid)
update(x, y, val, rt<<1);
else if(x > mid)
update(x, y, val, rt<<1|1);
else
{
update(x, mid, val, rt<<1);
update(mid+1, y, val, rt<<1|1);
}
pushup(rt);
}

long long query(int x, int y, int rt)
{
if(tree[rt].l == x && tree[rt].r == y)
return tree[rt].sum;
if(tree[rt].lazy)
pushdown(rt);  //向下更新枝叶的值
int mid = (tree[rt].l+tree[rt].r)>>1;
if(y <= mid)
return query(x, y, rt<<1);
else if(x > mid)
return query(x, y, rt<<1|1);
else
return query(x, mid, rt<<1) + query(mid+1, y, rt<<1|1);
}

int main()
{
int n, m;
int x, y;
string q;
while(~scanf("%d%d",&n,&m))
{
build(1, n, 1);
while(m--)
{
cin >> q;
scanf("%d%d",&x,&y);
if(q == "Q")
{
cout << query(x, y, 1) << endl;
}
else
{
long long val;
scanf("%lld",&val);
update(x, y, val, 1);
}
}
}
return 0;
}


D - Mayor's posters

POJ - 2528                    

E - Just a Hook

HDU - 1698                    

区间更新(值替换)及区间求和,和C一样的做法,只不过在处理lazy及sum时 += 换为了 =。

AC代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX = 100010;
int ans;
struct node
{
int l, r;
int sum, lazy;
} tree[MAX<<2];

void pushup(int rt)
{
tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}

void pushdown(int rt) //延迟操作,更新当前结点的叶子
{
int len = tree[rt].r - tree[rt].l + 1;
tree[rt<<1].sum = tree[rt].lazy*(len-len/2);
tree[rt<<1|1].sum = tree[rt].lazy*(len/2);
tree[rt<<1].lazy = tree[rt].lazy;
tree[rt<<1|1].lazy = tree[rt].lazy;
tree[rt].lazy = 0;
}

void build(int l, int r, int rt)
{
tree[rt].l = l;
tree[rt].r = r;
tree[rt].sum = tree[rt].lazy = 0;
if(l == r)
{
tree[rt].sum = 1;
return ;
}
int mid = (l+r)>>1;
//递归建树
build(l, mid, rt<<1);
build(mid+1, r, rt<<1|1);
pushup(rt);
}

void update(int x, int y, int val, int rt)
{
//更新这个区间的值
if(tree[rt].l == x && tree[rt].r == y)
{
tree[rt].lazy = val;
tree[rt].sum = (y-x+1)*val;
return ;
}
if(tree[rt].lazy)
pushdown(rt);  //向下更新枝叶的值
int mid = (tree[rt].l+tree[rt].r)>>1;
if(y <= mid)
update(x, y, val, rt<<1);
else if(x > mid)
update(x, y, val, rt<<1|1);
else
{
update(x, mid, val, rt<<1);
update(mid+1, y, val, rt<<1|1);
}
pushup(rt);
}

int query(int x, int y, int rt)
{
if(tree[rt].l == x && tree[rt].r == y)
return tree[rt].sum;
if(tree[rt].lazy)
pushdown(rt);  //向下更新枝叶的值
int mid = (tree[rt].l+tree[rt].r)>>1;
if(y <= mid)
return query(x, y, rt<<1);
else if(x > mid)
return query(x, y, rt<<1|1);
else
return query(x, mid, rt<<1) + query(mid+1, y, rt<<1|1);
}

int main()
{
int T;
int n, m;
int x, y, z;
scanf("%d",&T);
for(int i = 1; i <= T; ++i)
{
ans = 0;
scanf("%d%d",&n,&m);
build(1, n, 1);
while(m--)
{
scanf("%d%d%d",&x,&y,&z);
update(x, y, z, 1);
}
ans = query(1, n, 1);
printf("Case %d: The total value of the hook is %d.\n",i,ans);
}
return 0;
}


F - Count the Colors

ZOJ - 1610                    

G - Balanced Lineup

POJ - 3264                    

查询区间最大值与最小值之差。

AC代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX = 200010;
int ans1, ans2;
struct node
{
int l, r;
int Max, Min;
} tree[MAX<<2];

void pushup(int rt)
{
tree[rt].Max = max(tree[rt<<1].Max, tree[rt<<1|1].Max);
tree[rt].Min = min(tree[rt<<1].Min, tree[rt<<1|1].Min);
}

void build(int l, int r, int rt)
{
tree[rt].l = l;
tree[rt].r = r;
if(l == r) //叶子结点
{
scanf("%d",&tree[rt].Max);
tree[rt].Min = tree[rt].Max;
return ;
}
int mid = (l+r)>>1;
//递归建树
build(l, mid, rt<<1);
build(mid+1, r, rt<<1|1);
pushup(rt);
}

void update(int pos, int val, int rt)
{
//更新这个区间的值
if(tree[rt].l == tree[rt].r)
{
tree[rt].Max = tree[rt].Min = val;
return ;
}
int mid = (tree[rt].l+tree[rt].r)>>1;
if(pos <= mid)
update(pos, val, rt<<1);
else
update(pos, val, rt<<1|1);
pushup(rt);
}

void qMax(int x, int y, int rt)
{
if(tree[rt].l == x && tree[rt].r == y)
{
ans1 = max(ans1, tree[rt].Max);
return ;
}
int mid = (tree[rt].l+tree[rt].r)>>1;
if(y <= mid)
qMax(x, y, rt<<1);
else if(x > mid)
qMax(x, y, rt<<1|1);
else
{
qMax(x, mid, rt<<1);
qMax(mid+1, y, rt<<1|1);
}
}

void qMin(int x, int y, int rt)
{
if(tree[rt].l == x && tree[rt].r == y)
{
ans2 = min(ans2, tree[rt].Min);
return ;
}
int mid = (tree[rt].l+tree[rt].r)>>1;
if(y <= mid)
qMin(x, y, rt<<1);
else if(x > mid)
qMin(x, y, rt<<1|1);
else
{
qMin(x, mid, rt<<1);
qMin(mid+1, y, rt<<1|1);
}
}

int main()
{
int n, m;
int x, y;
while(~scanf("%d%d",&n,&m))
{
build(1, n, 1);
while(m--)
{
ans1 = 0;
ans2 = INF;
scanf("%d%d",&x,&y);
qMax(x, y, 1);
qMin(x, y, 1);
printf("%d\n",ans1-ans2);
}
}
return 0;
}


H - Can you answer these queries?

HDU - 4027                    

区间更新及求和。

由于对数据开方后区间和没法与更新前的区间和建立递推关系,所以无法和C题一样处理数据。

不过最大的数(2^63)开7次方后也会变成1,所以我们每次直接更新到叶子结点,然后把叶子结点都已无法更新的根节点及叶子结点都标记一下,下次更新时略过就好了。

AC代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX = 100010;
struct node
{
int l, r;
long long sum;
bool flag;
} tree[MAX<<2];

void pushup(int rt)
{
tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
tree[rt].flag = tree[rt<<1].flag & tree[rt<<1|1].flag; //叶子结点是否已都更新到无法更新
}

void build(int l, int r, int rt)
{
tree[rt].l = l;
tree[rt].r = r;
tree[rt].sum = tree[rt].flag = 0;
if(l == r)
{
scanf("%lld",&tree[rt].sum);
if(tree[rt].sum <= 1) tree[rt].flag = 1;
return ;
}
int mid = (l+r)>>1;
//递归建树
build(l, mid, rt<<1);
build(mid+1, r, rt<<1|1);
pushup(rt);
}

void update(int x, int y, int rt)
{
if(tree[rt].flag) return ;  //这是一步是关键,省下了很多无用的操作
//更新这个区间的值
if(tree[rt].l == tree[rt].r)
{
tree[rt].sum = (long long)sqrt(tree[rt].sum*1.0);
if(tree[rt].sum <= 1) tree[rt].flag = 1;
return ;
}
int mid = (tree[rt].l+tree[rt].r)>>1;
if(y <= mid)
update(x, y, rt<<1);
else if(x > mid)
update(x, y, rt<<1|1);
else
{
update(x, mid, rt<<1);
update(mid+1, y, rt<<1|1);
}
pushup(rt);
}

long long query(int x, int y, int rt)
{
if(tree[rt].l == x && tree[rt].r == y)
{
return tree[rt].sum;
}
int mid = (tree[rt].l+tree[rt].r)>>1;
if(y <= mid)
return query(x, y, rt<<1);
else if(x > mid)
return query(x, y, rt<<1|1);
else
return query(x, mid, rt<<1) + query(mid+1, y, rt<<1|1);
}

int main()
{
int n, m;
int q, x, y;
int cou = 0;
while(~scanf("%d",&n))
{
printf("Case #%d:\n",++cou);
build(1, n, 1);
scanf("%d",&m);
while(m--)
{
scanf("%d%d%d",&q,&x,&y);
if(x > y) swap(x, y);
if(q == 1)
{
cout << query(x, y, 1) << endl;
}
else
{
update(x, y, 1);
}
}
puts("");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: