总结一下这段时间所写的线段树题目,觉得好久没写博客了 =、=
UVA 12299 RMQ with Shifts
题目链接:http://vjudge.net/contest/view.action?cid=51165#problem/H
思路:直接上的挑战程序上的模板,需要注意输入格式及这种开区间写法带来的细节问题
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<sstream>
#include<cmath>
#include<climits>
#include<string>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<ctime>
using namespace std;
int n;
int dat[305000];
void init(int n_)
{
n = 1;
while(n < n_)
n *= 2;
for(int i = 0; i < 2 * n - 1; i++)
dat[i] = INT_MAX;
}
void update(int k, int a)
{
k += n - 1;
dat[k] = a;
while(k > 0)
{
k = (k - 1) / 2;
dat[k] = min(dat[2 * k + 1], dat[2 * k + 2]);
}
}
int query(int a, int b, int k, int l, int r)
{
if(r <= a || b <= l)
return INT_MAX;
if(a <= l && r <= b)
return dat[k];
else
{
int vl = query(a, b, 2 * k + 1, l, (l + r) / 2);
int vr = query(a, b, 2 * k + 2, (l + r) / 2, r);
return min(vl, vr);
}
}
int b[200000];
int main()
{
int q, n_;
while (~scanf("%d%d", &n_, &q))
{
init(n_);
char s[20];
for(int i = 0; i < n_; i++)
{
int a;
scanf("%d", &a);
update(i, a);
}
while(q--)
{
scanf(" %c%*c%*c%*c%*c", s);
if(s[0] == 'q')
{
int x, y;
scanf("(%d,%d)", &x, &y);
printf("%d\n", query(x - 1, y, 0, 0, n));
}
else
{
char c;
int i = 0;
scanf("(");
while(scanf("%d%c", &b[i], &c))
{
b[i]--;
i++;
if(c == ')')
break;
}
i--;
int t = dat[b[0] + n - 1];
for(int j = 0 ; j < i; j++)
{
update(b[j], dat[b[j + 1] + n - 1]);
}
update(b[i], t);
}
}
}
return 0;
}
HDU 3974 Assign the task
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3974
思路:C x表示查询x节点的值,T x y表示更新x节点及其子节点的值为y,使用先序遍历和懒惰标记(懒惰标记指在进行区间更新时,只更新父节点的值,这样在之后查询时找到维护区间的父节点即可,而在以后需要更新区间或是查询时,如果找到被标记的点,而该点并非要找的那个,我们就对其儿子节点进行更新,并将儿子节点标记,父节点改为不标记)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
int ln[50010], rn[50010], ji = 0, sd[500000], dn;
vector<int> gra[50010];
void dfs(int x)
{
ln[x] = ji++;
for (int i = 0; i < gra[x].size(); ++i)
dfs(gra[x][i]);
rn[x] = ji;
}
void update(int k, int l, int r, int a, int b, int t)
{
if (r <= a || l >= b)
return ;
if (l >= a && r <= b)
{
sd[k] = t;
return ;
}
if (sd[k] != -2)
{
sd[2 * k + 1] = sd[2 * k + 2] = sd[k];
sd[k] = -2;
}
update(2 * k + 1, l, (l + r) / 2, a, b, t);
update(2 * k + 2, (l + r) / 2, r, a, b, t);
}
int query(int k, int l, int r, int dd)
{
if (sd[k] != -2)
return sd[k];
if (dd < (l + r) / 2)
return query(2 * k + 1, l, (l + r) / 2, dd);
else
return query(2 * k + 2, (l + r) / 2, r, dd);
}
int main()
{
int t;
scanf("%d", &t);
for (int cas = 1; cas <= t; ++cas)
{
printf("Case #%d:\n", cas);
memset(sd, -1, sizeof(sd));
int n, i, bos = 0, m;
scanf("%d", &n);
for (dn = 1; dn < n; dn *= 2);
for (i = 0; i <= n; ++i)
{
bos += i;
gra[i].clear();
}
ji = 0;
for (i = 0; i < n - 1; ++i)
{
int x, y;
scanf("%d%d", &x, &y);
bos -= x;
gra[y].push_back(x);
}
dfs(bos);
scanf("%d", &m);
while (m--)
{
char ch[10];
scanf(" %s", ch);
if (*ch == 'T')
{
int a, b;
scanf("%d%d", &a, &b);
update(0, 0, dn, ln[a], rn[a], b);
}
else
{
int a;
scanf("%d", &a);
printf("%d\n", query(0, 0, dn, ln[a]));
}
}
}
return 0;
}
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3333
思路:由于数据过大,故需要离散化处理,可以使用map来映射,另外需注意处理重复数字
#include <iostream>
#include <cstdio>
#include <map>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 100010;
ll bit[maxn], ans[maxn];
int N, M, cnt, d[maxn];
map <int, int> m;
struct node
{
int l;
int r;
int id;
} a[maxn];
int cmp(node a, node b)
{
return a.r < b.r;
}
void add(int i, int d)
{
while(i <= N)
{
bit[i] += d;
i += i & (-i);
}
}
ll sum(int i)
{
ll s = 0;
while(i)
{
s += bit[i];
i -= i & (-i);
}
return s;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int k = 1;
memset(bit, 0, sizeof(bit));
m.clear();
scanf("%d", &N);
for(int i = 1; i <= N; i++)
scanf("%d", &d[i]);
scanf("%d", &M);
for(int i = 0; i < M; i++)
{
scanf("%d%d", &a[i].l, &a[i].r);
a[i].id = i;
}
sort(a, a + M, cmp);
for(int i = 0; i < M; i++)
{
for(; k <= a[i].r; k++)
{
if(m[d[k]])
add(m[d[k]], -d[k]);
m[d[k]] = k;
add(k, d[k]);
}
ans[a[i].id] = sum(a[i].r) - sum(a[i].l - 1);
}
for(int i = 0; i < M; i++)
printf("%I64d\n", ans[i]);
}
return 0;
}
POJ 3468 A Simple Problem with Integers
题目链接:http://poj.org/problem?id=3468
思路:用两个树状数组分别维护一个区间内所有元素共同加上的值,两一个维护除去所加值之外其他元素的和
#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
#include <math.h>
#include <algorithm>
const int maxn = 200100;
using namespace std;
typedef long long ll;
ll bit1[maxn], bit2[maxn];
int n,q;
ll sum(ll * b, int i)
{
ll s = 0;
while(i)
{
s += b[i];
i -= i & (-i);
}
return s;
}
void add(ll * b, int i, int v)
{
while(i <= n)
{
b[i] += v;
i += i & (-i);
}
}
int main()
{
while(~scanf("%d%d",&n,&q))
{
for(int i = 1; i <= n; i++)
{
int a;
scanf("%d", &a);
add(bit1, i, a);
}
for(int i = 0; i < q; i++)
{
char c;
int l, r, x;
scanf(" %c", &c);
if(c == 'C')
{
scanf("%d%d%d", &l, &r, &x);
add(bit1, l, (-x) * (l - 1));
add(bit2, l, x);
add(bit1, r + 1, x * r);
add(bit2, r + 1, -x);
}
else
{
scanf("%d%d",&l,&r);
ll res = 0;
res += sum(bit1, r) + sum(bit2, r) * r;
res -= sum(bit1, l - 1) + sum(bit2, l - 1) * (l - 1);
printf("%I64d\n", res);
}
}
}
}