线段树的成段更新,需要用到延迟标记
就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候
否则就会退化到O(n)的复杂度
1.hdu 1698 Just a Hook
大意是每次把某一段所有数的值改变成某个值,最后求总和。
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#define MAXN 100005
#define INF 100000000
#define eps 1e-11
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
struct node
{
int left, right, mid;
int cover, len, sum;
}tree[4 * MAXN];
void make_tree(int s, int e, int C)
{
tree[C].left = s;
tree[C].right = e;
tree[C].mid = (s + e) / 2;
tree[C].len = tree[C].right - tree[C].left + 1;
tree[C].cover = 1;
tree[C].sum = tree[C].cover * tree[C].len;
if(s == e)
return;
make_tree(s, tree[C].mid, L(C));
make_tree(tree[C].mid + 1, e, R(C));
}
void up(int C)
{
tree[C].sum = tree[L(C)].sum + tree[R(C)].sum;
}
void down(int C)
{
if(tree[C].cover)
{
tree[L(C)].cover = tree[R(C)].cover = tree[C].cover;
tree[L(C)].sum = tree[L(C)].len * tree[L(C)].cover;
tree[R(C)].sum = tree[R(C)].len * tree[R(C)].cover;
tree[C].cover = 0;
}
}
void update(int s, int e, int k, int C)
{
if(tree[C].left >= s && tree[C].right <= e)
{
tree[C].cover = k;
tree[C].sum = tree[C].cover * tree[C].len;
return;
}
down(C);
if(tree[C].mid < s) update(s, e, k, R(C));
else if(tree[C].mid >= e) update(s, e, k, L(C));
else
{
update(s, tree[C].mid, k, L(C));
update(tree[C].mid + 1, e, k, R(C));
}
up(C);
}
int main()
{
//freopen("d:/data.in","r",stdin);
//freopen("d:/data.out","w",stdout);
int t, n, i, x, y, z, cas = 0, m;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
make_tree(1, n, 1);
scanf("%d", &m);
for(i = 0; i < m; i++)
{
scanf("%d%d%d", &x, &y, &z);
update(x, y, z, 1);
}
printf("Case %d: The total value of the hook is %d.\n", ++cas, tree[1].sum);
}
return 0;
}
2. POJ 3468A Simple Problem with Integers
这题比上面那道的操作稍微复杂了一点,把某个区间的数统一加上某个值。
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#define MAXN 100005
#define INF 100000000
#define eps 1e-11
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
struct node
{
int left, right, mid;
__int64 cover, len;
__int64 sum;
}tree[4 * MAXN];
__int64 a[100005];
void up(int C)
{
tree[C].sum = tree[L(C)].sum + tree[R(C)].sum;
}
void down(int C)
{
if(tree[C].cover)
{
tree[L(C)].cover += tree[C].cover;
tree[R(C)].cover += tree[C].cover;
tree[L(C)].sum += tree[C].cover * tree[L(C)].len;
tree[R(C)].sum += tree[C].cover * tree[R(C)].len;
tree[C].cover = 0;
}
}
void make_tree(int s, int e, int C)
{
tree[C].left = s;
tree[C].right = e;
tree[C].mid = (s + e) / 2;
tree[C].cover = 0;
tree[C].sum = 0;
tree[C].len = tree[C].right - tree[C].left + 1;
if(s == e)
{
tree[C].sum = a[s];
return;
}
make_tree(s, tree[C].mid, L(C));
make_tree(tree[C].mid + 1, e, R(C));
up(C);
}
void update(int s, int e, __int64 k, int C)
{
if(tree[C].left >= s && tree[C].right <= e)
{
tree[C].cover += k;
tree[C].sum += k * tree[C].len;
return;
}
down(C);
if(tree[C].mid < s) update(s, e, k, R(C));
else if(tree[C].mid >= e) update(s, e, k, L(C));
else
{
update(s, tree[C].mid, k, L(C));
update(tree[C].mid + 1, e, k, R(C));
}
up(C);
}
__int64 query(int s, int e, int C)
{
if(tree[C].left >= s && tree[C].right <= e)
return tree[C].sum;
down(C);
__int64 tmp = 0;
if(tree[C].mid < s) tmp += query(s, e, R(C));
else if(tree[C].mid >= e) tmp += query(s, e, L(C));
else
{
tmp += query(s, tree[C].mid, L(C));
tmp += query(tree[C].mid + 1, e, R(C));
}
return tmp;
}
int main()
{
//freopen("d:/data.in","r",stdin);
//freopen("d:/data.out","w",stdout);
int n, m, i, x, y;
__int64 z;
char s[5];
scanf("%d%d", &n, &m);
for(i = 1; i <= n; i++)
scanf("%I64d", &a[i]);
make_tree(1, n, 1);
while(m--)
{
scanf("%s", s);
if(s[0] == 'Q')
{
scanf("%d%d", &x, &y);
printf("%I64d\n",query(x, y, 1));
}
else if(s[0] == 'C')
{
scanf("%d%d%I64d", &x, &y, &z);
update(x, y, z, 1);
}
}
return 0;
}
3.poj 2528 Mayor’s posters
大意就是往墙上按区间涂色,看最后能看见的颜色个数
比较麻烦的就是离散化的事情,先把所有的坐标存下来,去重后映射一下,这时就有些问题了,比如原始坐标是1, 3, 6, 10,映射完了是0, 1, 2, 3,3和6本来中间还有几块的,离散完了成相邻的了,所以这里就要处理一下,1,3,6, 10就要处理成1,2,3,4,6,7,10之类的,总之相邻的坐标之差如果大于1了,就在中间添加一个适当的数表示这之间还有块。
然后就建线段树,查询的时候查整个线段树中颜色的个数就行了。
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#define MAXN 10005
#define INF 100000000
#define eps 1e-11
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
struct node
{
int left, right, mid;
int cover;
}tree[16 * MAXN];
int a[4 * MAXN];
int l[MAXN];
int r[MAXN];
int ans, n;
bool used[MAXN];
void make_tree(int s, int e, int C)
{
tree[C].left = s;
tree[C].right = e;
tree[C].cover = -1;
tree[C].mid = (s + e) / 2;
if(s == e) return;
make_tree(s, tree[C].mid, L(C));
make_tree(tree[C].mid + 1, e, R(C));
}
void down(int C)
{
if(tree[C].cover != -1)
{
tree[L(C)].cover = tree[R(C)].cover = tree[C].cover;
tree[C].cover = -1;
}
}
void update(int s, int e, int k, int C)
{
if(tree[C].left >= s && tree[C].right <= e)
{
tree[C].cover = k;
return;
}
down(C);
if(tree[C].mid < s) update(s, e, k, R(C));
else if(tree[C].mid >= e) update(s, e, k, L(C));
else
{
update(s, tree[C].mid, k, L(C));
update(tree[C].mid + 1, e, k, R(C));
}
}
void query(int C)
{
if(tree[C].cover != -1)
{
if(!used[tree[C].cover])
{
ans++;
used[tree[C].cover] = 1;
}
return;
}
if(tree[C].left == tree[C].right)
return;
query(L(C));
query(R(C));
}
int b_search(int v)
{
int left = 0, right = n - 1;
while(left <= right)
{
int mid = (left + right) / 2;
if(a[mid] == v) return mid;
else if(a[mid] > v) right = mid - 1;
else left = mid + 1;
}
return 0;
}
int main()
{
//freopen("d:/data.in","r",stdin);
//freopen("d:/data.out","w",stdout);
int t, m, i;
scanf("%d", &t);
while(t--)
{
ans = 0;
memset(used, 0, sizeof(used));
scanf("%d", &m);
int cnt = 0;
for(i = 0; i < m; i++)
{
scanf("%d%d", &l[i], &r[i]);
a[cnt++] = l[i];
a[cnt++] = r[i];
}
sort(a, a + cnt);
n = unique(a, a + cnt) - a;
for(i = n - 1; i > 0; i--)
{
if(a[i] - a[i - 1] != 1) a[n++] = a[i - 1] + 1;
}
sort(a, a + n);
n = unique(a, a + n) - a;
make_tree(0, n - 1, 1);
for(i = 0; i < m; i++)
{
int ll = b_search(l[i]);
//printf("ll %d\n", ll);
int rr = b_search(r[i]);
update(ll, rr, i, 1);
//printf("rr %d\n", rr);
}
query(1);
printf("%d\n", ans);
}
return 0;
}
然后更神的是这道题可以用并查集做
从acmol的空间看的http://blog.acmol.com/?p=751
/*
ID: sdj22251
PROG: inflate
LANG: C++
*/
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#define MAXN 9*9*9*9
#define INF 1000000000
using namespace std;
int hash[10000005];
int father[40005];
int a[10005], b[10005], x[20005];
bool v[40005];
int find(int x)
{
if(father[x] == -1) return x;
int t = find(father[x]);
father[x] = t;
return t;
}
int main()
{
int T, n;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%d%d", &a[i], &b[i]);
x[2 * i] = a[i];
x[2 * i + 1] = b[i];
}
sort(x, x + 2 * n);
int cnt = unique(x, x + 2 * n) - x;
hash[x[0]] = 0;
for(int i = 1; i < cnt; i++)
{
int flag = 0;
if(x[i - 1] + 1 != x[i]) flag = 1;
hash[x[i]] = hash[x[i - 1]] + flag + 1;
}
int ans = 0;
memset(v, 0, sizeof(v));
memset(father, -1, sizeof(father));
for(int i = n - 1; i >= 0; i--)
{
bool flag = false;
int fa = find(hash[a[i]]), fb;
for(int j = hash[b[i]]; j >= hash[a[i]]; j = fb - 1)
{
fb = find(j);
if(!v[fb]) v[fb] = flag = true;
if(fa != fb) father[fb] = fa;
}
if(flag) ans++;
}
printf("%d\n", ans);
}
return 0;
}
4.POJ 2777 Count Color
几乎与2528一摸一样的题,只不过更加裸了
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#define MAXN 100005
#define INF 100000000
#define eps 1e-11
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
struct node
{
int left, right, mid;
int cover;
}tree[4 * MAXN];
bool used[33];
int ans;
void make_tree(int s, int e, int C)
{
tree[C].left = s;
tree[C].right = e;
tree[C].cover = 1;
tree[C].mid = (s + e) / 2;
if(s == e) return;
make_tree(s, tree[C].mid, L(C));
make_tree(tree[C].mid + 1, e, R(C));
}
void down(int C)
{
if(tree[C].cover != -1)
{
tree[L(C)].cover = tree[R(C)].cover = tree[C].cover;
tree[C].cover = -1;
}
}
void update(int s, int e, int k, int C)
{
if(tree[C].left >= s && tree[C].right <= e)
{
tree[C].cover = k;
return;
}
down(C);
if(tree[C].mid < s) update(s, e, k, R(C));
else if(tree[C].mid >= e) update(s, e, k, L(C));
else
{
update(s, tree[C].mid, k, L(C));
update(tree[C].mid + 1, e, k, R(C));
}
}
void query(int s, int e, int C)
{
if(tree[C].cover != -1)
{
if(!used[tree[C].cover])
{
ans++;
used[tree[C].cover] = 1;
}
return;
}
if(tree[C].left == tree[C].right)
return;
if(tree[C].mid < s) query(s, e, R(C));
else if(tree[C].mid >= e) query(s, e, L(C));
else
{
query(s, tree[C].mid, L(C));
query(tree[C].mid + 1, e, R(C));
}
}
int main()
{
//freopen("d:/data.in","r",stdin);
//freopen("d:/data.out","w",stdout);
int n, m, t, x, y, z, i;
char s[5];
scanf("%d%d%d", &n, &m, &t);
make_tree(1, n, 1);
while(t--)
{
scanf("%s", s);
if(s[0] == 'C')
{
scanf("%d%d%d", &x, &y, &z);
if(x > y) swap(x, y);
update(x, y, z, 1);
}
else
{
scanf("%d%d", &x, &y);
ans = 0;
memset(used, 0, sizeof(used));
query(x, y, 1);
printf("%d\n", ans);
}
}
return 0;
}
分享到:
相关推荐
大量线段树题目 zoj 1610 线段覆盖 poj 2777 线段覆盖 poj 2528 需要离散化,建树不同,需要处理不同->注意这组数据 3 1 10 1 3 6 10 the ans is 3. hdu 1754 求区间最大值 hdu 1166 求区间和 hdu 1698 成段更新 ...
有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...
有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...
有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...
有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...
有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...
有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...
有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...
有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出...