[题解]线段树专题测试2017.1.21



  很单纯的一道线段树题。稍微改一下pushDown()就行了。

Code(线段树模板竟然没超100行)

  1 #include<iostream>
  2 #include<sstream>
  3 #include<cstdio>
  4 #include<cmath>
  5 #include<cstdlib>
  6 #include<cstring>
  7 #include<cctype>
  8 #include<queue>
  9 #include<set>
 10 #include<map>
 11 #include<stack>
 12 #include<vector>
 13 #include<algorithm>
 14 using namespace std;
 15 typedef bool boolean;
 16 #ifdef    WIN32
 17 #define AUTO "%I64d"
 18 #else
 19 #define AUTO "%lld"
 20 #endif
 21 #define smin(a, b) (a) = min((a), (b))
 22 #define smax(a, b) (a) = max((a), (b))
 23 template<typename T>
 24 inline void readInteger(T& u){
 25     char x;
 26     int aFlag = 1;
 27     while(!isdigit((x = getchar())) && x != ‘-‘);
 28     if(x == ‘-‘){
 29         aFlag = -1;
 30         x = getchar();
 31     }
 32     for(u = x - ‘0‘; isdigit((x = getchar())); u = u * 10 + x - ‘0‘);
 33     ungetc(x, stdin);
 34     u *= aFlag;
 35 }
 36
 37 typedef class SegTreeNode {
 38     public:
 39         long long sum;
 40         int l, r;
 41         SegTreeNode *left, *right;
 42         int lazy;
 43         SegTreeNode():sum(0), l(0), r(0), left(NULL), right(NULL), lazy(0){        }
 44         SegTreeNode(int l, int r):sum(0), l(l), r(r), left(NULL), right(NULL), lazy(0){        }
 45
 46         inline void pushUp(){
 47             this->sum = this->left->sum + this->right->sum;
 48         }
 49
 50         inline void pushDown(){
 51             left->sum = (left->r - left->l + 1) * 1LL * lazy;
 52             left->lazy = lazy;
 53             right->sum = (right->r - right->l + 1) * 1LL * lazy;
 54             right->lazy = lazy;
 55             lazy = 0;
 56         }
 57 }SegTreeNode;
 58
 59 typedef class SegTree {
 60     public:
 61         SegTreeNode* root;
 62
 63         SegTree():root(NULL){        }
 64         SegTree(int size, int* list){
 65             build(root, 1, size, list);
 66         }
 67
 68         void build(SegTreeNode*& node, int l, int r, int* list){
 69             node = new SegTreeNode(l, r);
 70             if(l == r){
 71                 node->sum = list[l];
 72                 return;
 73             }
 74             int mid = (l + r) >> 1;
 75             build(node->left, l, mid, list);
 76             build(node->right, mid + 1, r, list);
 77             node->pushUp();
 78         }
 79
 80         void update(SegTreeNode*& node, int l, int r, long long val){
 81             if(node->l == l && node->r == r){
 82                 node->sum = (r - l + 1) * val;
 83                 node->lazy = val;
 84                 return;
 85             }
 86             if(node->lazy)    node->pushDown();
 87             int mid = (node->l + node->r) >> 1;
 88             if(r <= mid)    update(node->left, l, r, val);
 89             else if(l > mid)    update(node->right, l, r, val);
 90             else{
 91                 update(node->left, l, mid, val);
 92                 update(node->right, mid + 1, r, val);
 93             }
 94             node->pushUp();
 95         }
 96
 97         long long query(SegTreeNode*& node, int l, int r){
 98             if(node->l == l && node->r == r){
 99                 return node->sum;
100             }
101             if(node->lazy)    node->pushDown();
102             int mid = (node->l + node->r) >> 1;
103             if(r <= mid)    return query(node->left, l, r);
104             if(l > mid)        return query(node->right, l, r);
105             return query(node->left, l, mid) + query(node->right, mid + 1, r);
106         }
107 }SegTree;
108
109 int n, m;
110 int* list;
111 SegTree st;
112
113 inline void init(){
114     readInteger(n);
115     list = new int[(const int)(n + 1)];
116     for(int i = 1; i <= n; i++)
117         readInteger(list[i]);
118     readInteger(m);
119     st = SegTree(n, list);
120 }
121
122 inline void solve(){
123     char cmd[10];
124     int a, b, c;
125     while(m--){
126         scanf("%s", cmd);
127         readInteger(a);
128         readInteger(b);
129         if(cmd[0] == ‘m‘){
130             readInteger(c);
131             st.update(st.root, a, b, c);
132         }else{
133             long long res = st.query(st.root, a, b);
134             printf(AUTO"\n", res);
135         }
136     }
137 }
138
139 int main(){
140     freopen("setsum.in", "r", stdin);
141     freopen("setsum.out", "w", stdout);
142     init();
143     solve();
144     return 0;
145 }


  dfs序弄一下然后加一个树状数组/线段树就可以轻松应付后面的操作,然而我不小心在建树的时候,用下标为节点编号进行建树而不是访问时间(这个问题很诡异,看着数组完全不知道在干什么),于是愉快地只有10分。

  用树状数组要快一点,只不过我比较懒,一二题的线段树模板差距不但,粘过来改一下就行了。

Code

  1 #include<iostream>
  2 #include<sstream>
  3 #include<cstdio>
  4 #include<cmath>
  5 #include<cstdlib>
  6 #include<cstring>
  7 #include<cctype>
  8 #include<queue>
  9 #include<set>
 10 #include<map>
 11 #include<stack>
 12 #include<vector>
 13 #include<algorithm>
 14 using namespace std;
 15 typedef bool boolean;
 16 #ifdef    WIN32
 17 #define AUTO "%I64d"
 18 #else
 19 #define AUTO "%lld"
 20 #endif
 21 #define smin(a, b) (a) = min((a), (b))
 22 #define smax(a, b) (a) = max((a), (b))
 23 template<typename T>
 24 inline void readInteger(T& u){
 25     char x;
 26     int aFlag = 1;
 27     while(!isdigit((x = getchar())) && x != ‘-‘);
 28     if(x == ‘-‘){
 29         aFlag = -1;
 30         x = getchar();
 31     }
 32     for(u = x - ‘0‘; isdigit((x = getchar())); u = u * 10 + x - ‘0‘);
 33     ungetc(x, stdin);
 34     u *= aFlag;
 35 }
 36
 37 typedef class SegTreeNode {
 38     public:
 39         long long sum;
 40         int l, r;
 41         SegTreeNode *left, *right;
 42         SegTreeNode():sum(0), l(0), r(0), left(NULL), right(NULL){        }
 43         SegTreeNode(int l, int r):sum(0), l(l), r(r), left(NULL), right(NULL){        }
 44         inline void pushUp(){
 45             this->sum = this->left->sum + this->right->sum;
 46         }
 47 }SegTreeNode;
 48
 49 typedef class SegTree {
 50     public:
 51         SegTreeNode* root;
 52
 53         SegTree():root(NULL){        }
 54         SegTree(int size, int* list, int* keyer){
 55             build(root, 1, size, list, keyer);
 56         }
 57
 58         void build(SegTreeNode*& node, int l, int r, int* list, int* keyer){
 59             node = new SegTreeNode(l, r);
 60             if(l == r){
 61                 node->sum = list[keyer[l]];
 62                 return;
 63             }
 64             int mid = (l + r) >> 1;
 65             build(node->left, l, mid, list, keyer);
 66             build(node->right, mid + 1, r, list, keyer);
 67             node->pushUp();
 68         }
 69
 70         void update(SegTreeNode*& node, int index, long long val){
 71             if(node->l == index && node->r == index){
 72                 node->sum += val;
 73                 return;
 74             }
 75             int mid = (node->l + node->r) >> 1;
 76             if(index <= mid)    update(node->left, index, val);
 77             else update(node->right, index, val);
 78             node->pushUp();
 79         }
 80
 81         long long query(SegTreeNode*& node, int l, int r){
 82             if(node->l == l && node->r == r){
 83                 return node->sum;
 84             }
 85             int mid = (node->l + node->r) >> 1;
 86             if(r <= mid)    return query(node->left, l, r);
 87             if(l > mid)        return query(node->right, l, r);
 88             return query(node->left, l, mid) + query(node->right, mid + 1, r);
 89         }
 90 }SegTree;
 91
 92 typedef class Edge{
 93     public:
 94         int end;
 95         int next;
 96         Edge(const int end = 0, const int next = 0):end(end), next(next){        }
 97 }Edge;
 98
 99 typedef class MapManager{
100     public:
101         int ce;
102         int *h;
103         Edge* edges;
104         MapManager():ce(0), h(NULL), edges(NULL){        }
105         MapManager(int points, int limits):ce(0){
106             h = new int[(const int)(points + 1)];
107             edges = new Edge[(const int)(limits + 1)];
108             memset(h, 0, sizeof(int) * (points + 1));
109         }
110         inline void addEdge(int from, int end){
111             edges[++ce] = Edge(end, h[from]);
112             h[from] = ce;
113         }
114         inline void addDoubleEdge(int from, int end){
115             addEdge(from, end);
116             addEdge(end, from);
117         }
118         Edge& operator [](int pos){
119             return edges[pos];
120         }
121 }MapManager;
122
123 #define m_begin(g, i) (g).h[(i)]
124
125 int n, m;
126 int cnt = 0;
127 int* list;
128 int* keyer;
129 int* visitID;
130 int* exitID;
131 SegTree st;
132 MapManager g;
133
134 void dfs(int node, int last){
135     visitID[node] = ++cnt;
136     keyer[cnt] = node;
137     for(int i = m_begin(g, node); i != 0; i = g[i].next){
138         int &e = g[i].end;
139         if(e == last)    continue;
140         dfs(e, node);
141     }
142     exitID[node] = cnt;
143 }
144
145 inline void init(){
146     readInteger(n);
147     list = new int[(const int)(n + 1)];
148     g = MapManager(n, n * 2);
149     for(int i = 1; i <= n; i++)
150         readInteger(list[i]);
151     for(int i = 1, a, b; i < n; i++){
152         readInteger(a);
153         readInteger(b);
154         g.addDoubleEdge(a, b);
155     }
156     visitID = new int[(const int)(n + 1)];
157     exitID = new int[(const int)(n + 1)];
158     keyer = new int[(const int)(n + 1)];
159     dfs(1, 0);
160     readInteger(m);
161     st = SegTree(n, list, keyer);
162 }
163
164 inline void solve(){
165     char cmd[10];
166     int a, b;
167     while(m--){
168         scanf("%s", cmd);
169         readInteger(a);
170         if(cmd[0] == ‘m‘){
171             readInteger(b);
172             st.update(st.root, visitID[a], b);
173         }else{
174             long long res = st.query(st.root, visitID[a], exitID[a]);
175             printf(AUTO"\n", res);
176         }
177     }
178 }
179
180 int main(){
181     freopen("subtree.in", "r", stdin);
182     freopen("subtree.out", "w", stdout);
183     init();
184     solve();
185     return 0;
186 }



  第三题有更正,输入文件:matgcd.in,样例输入:2 2 3....,每个测试点限时:2000ms

  第三题正解ST表,建表(预处理)O(n * m * logn * logm),查询O(1)。用f[i][j][posx][posy]表示左上角为(i, j),宽度为2posx,高度为2posy的矩形的最大公约数来表示。至于状态转移就画个图:

  

  把划分出来的这四块拖出来gcd就行了。查询同理,只不过要特判单个点,只是一条线(又用st表)的特殊情况。

-->

  不过我并没有写st表,而是一种很粗暴的方法——树套树(据说线段树套线段树特别牛逼)。

  一个线段树负责一行的最大公约数。套外面的线段树就负责合并列的线段树。虽然理论上死得很惨(莫名其妙地多出了一个O(log2n * log2m)),但是可以加优化,查询的时候,查到的值为1,就return 1。实测效果不错,综合下来,windows随机数据才0.8s。(然而诡异的cena需要1.9s,指针户吃亏啊。。。)

Code(初次树套树比平衡树短)

  1 #include<iostream>
  2 #include<sstream>
  3 #include<cstdio>
  4 #include<cmath>
  5 #include<cstdlib>
  6 #include<cstring>
  7 #include<cctype>
  8 #include<queue>
  9 #include<set>
 10 #include<map>
 11 #include<stack>
 12 #include<vector>
 13 #include<algorithm>
 14 #include<ctime>
 15 using namespace std;
 16 typedef bool boolean;
 17 #ifdef    WIN32
 18 #define AUTO "%I64d"
 19 #else
 20 #define AUTO "%lld"
 21 #endif
 22 #define smin(a, b) (a) = min((a), (b))
 23 #define smax(a, b) (a) = max((a), (b))
 24 template<typename T>
 25 inline void readInteger(T& u){
 26     char x;
 27     int aFlag = 1;
 28     while(!isdigit((x = getchar())) && x != ‘-‘);
 29     if(x == ‘-‘){
 30         aFlag = -1;
 31         x = getchar();
 32     }
 33     for(u = x - ‘0‘; isdigit((x = getchar())); u = u * 10 + x - ‘0‘);
 34     ungetc(x, stdin);
 35     u *= aFlag;
 36 }
 37
 38 template<typename T>
 39 inline T gcd(T a, T b){
 40     return (b == 0) ? (a) : (gcd(b, a % b));
 41 }
 42
 43 template<typename T>
 44 class Matrix{
 45     public:
 46         T* p;
 47         int lines, rows;
 48         Matrix():p(NULL), lines(0), rows(0){        }
 49         Matrix(int rows, int lines):rows(rows), lines(lines){
 50             p = new T[rows * lines];
 51         }
 52         T* operator [](int pos){
 53             return p + pos * lines;
 54         }
 55 };
 56
 57 typedef class SegTreeNode1{
 58     public:
 59         int val;
 60         SegTreeNode1 *left, *right;
 61         SegTreeNode1():left(NULL), right(NULL), val(0){        }
 62
 63         inline void pushUp(){
 64             val = gcd(left->val, right->val);
 65         }
 66 }SegTreeNode1;
 67
 68 typedef class SegTree1 {
 69     public:
 70         SegTreeNode1* root;
 71
 72         SegTree1():root(NULL){        }
 73         SegTree1(int size, int* list){
 74             build(root, 1, size, list);
 75         }
 76
 77         void build(SegTreeNode1*& node, int l, int r, int* list){
 78             node = new SegTreeNode1();
 79             if(l == r){
 80                 node->val = list[l];
 81                 return;
 82             }
 83             int mid = (l + r) >> 1;
 84             build(node->left, l, mid, list);
 85             build(node->right, mid + 1, r, list);
 86             node->pushUp();
 87         }
 88
 89         int query(SegTreeNode1*& node, int l, int r, int from, int end){
 90             if(l == from && r == end)    return node->val;
 91             int mid = (l + r) >> 1;
 92             if(end <= mid)    return query(node->left, l, mid, from, end);
 93             if(from > mid)    return query(node->right, mid + 1, r, from, end);
 94             int a = query(node->left, l, mid, from, mid);
 95             if(a == 1)    return 1;
 96             int b = query(node->right, mid + 1, r, mid + 1, end);
 97             return gcd(a, b);
 98         }
 99 }SegTree1;
100
101 void merge(SegTreeNode1*& a, SegTreeNode1*& b, SegTreeNode1*& res){
102     res = new SegTreeNode1();
103     res->val = gcd(a->val, b->val);
104     if(a->left == NULL)    return;
105     merge(a->left, b->left, res->left);
106     merge(a->right, b->right, res->right);
107 }
108
109 typedef class SegTreeNode2 {
110     public:
111         SegTree1 val;
112         SegTreeNode2* left, *right;
113         SegTreeNode2():left(NULL), right(NULL){
114             val = SegTree1();
115         }
116
117         inline void pushUp(){
118             merge(left->val.root, right->val.root, val.root);
119         }
120 }SegTreeNode2;
121
122 typedef class SegTree2{
123     public:
124         SegTreeNode2* root;
125
126         SegTree2():root(NULL){        }
127         SegTree2(int n, int m, Matrix<int>& a){
128             build(root, 1, n, m, a);
129         }
130
131         void build(SegTreeNode2*& node, int l, int r, int m, Matrix<int>& a){
132             node = new SegTreeNode2();
133             if(l == r){
134                 node->val = SegTree1(m, a[l]);
135                 return;
136             }
137             int mid = (l + r) >> 1;
138             build(node->left, l, mid, m, a);
139             build(node->right, mid + 1, r, m, a);
140             node->pushUp();
141         }
142
143         int query(SegTreeNode2*& node, int l, int r, int from, int end, int m, int from1, int end1){
144             if(l == from && r == end){
145                 return node->val.query(node->val.root, 1, m, from1, end1);
146             }
147             int mid = (l + r) >> 1;
148             if(end <= mid)    return query(node->left, l, mid, from, end, m, from1, end1);
149             if(from > mid)    return query(node->right, mid + 1, r, from, end, m, from1, end1);
150             int a = query(node->left, l, mid, from, mid, m, from1, end1);
151             if(a == 1)    return 1;
152             int b = query(node->right, mid + 1, r, mid + 1, end, m, from1, end1);
153             return gcd(a, b);
154         }
155 }SegTree2;
156
157 int n, m, q;
158 Matrix<int> mat;
159 SegTree2 st;
160
161 inline void init(){
162     readInteger(n);
163     readInteger(m);
164     readInteger(q);
165     mat = Matrix<int>(n + 1, m + 1);
166     for(int i = 1; i <= n; i++){
167         for(int j = 1; j <= m; j++){
168             readInteger(mat[i][j]);
169         }
170     }
171     st = SegTree2(n, m, mat);
172 }
173
174 inline void solve(){
175     int x1, x2, y1, y2;
176     while(q--){
177         readInteger(x1);
178         readInteger(y1);
179         readInteger(x2);
180         readInteger(y2);
181         int res = st.query(st.root, 1, n, x1, x2, m, y1, y2);
182         printf("%d\n", res);
183     }
184 }
185
186 int main(){
187     freopen("matgcd.in", "r", stdin);
188     freopen("matgcd.out", "w", stdout);
189     init();
190     solve();
191     return 0;
192 }
时间: 2024-12-23 12:22:01

[题解]线段树专题测试2017.1.21的相关文章

vj线段树专题

vj线段树专题题解 单点更新模板 void build(int x,int l,int r){//sum[x]控制l-r区域 if(l==r){Sum[x]=num[l];return ;} int mid=l+((r-l)>>1); build(x<<1,l,mid); build(x<<1|1,mid+1,r); Sum[x]=Sum[x<<1]+Sum[x<<1|1]; } void add(int a,int b,int l,int r,

[kuangbin]带你飞之&#39;线段树&#39;专题(未完成)

// 带飞网址 https://vjudge.net/article/187 专题七 线段树 HDU 1166 敌兵布阵HDU 1754 I Hate It√ POJ 3468 A Simple Problem with IntegersPOJ 2528 Mayor's postersHDU 1698 Just a HookZOJ 1610 Count the ColorsPOJ 3264 Balanced LineupHDU 4027 Can you answer these queries?

POJ2182题解——线段树

POJ2182题解——线段树 2019-12-20 by juruoOIer 1.线段树简介(来源:百度百科) 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN).而未优化的空间复杂度为2N,实际应用时一般还要开4N的数组以免越界,因此有时需要离散化让空间压缩. 2.线段树实际应用 上面的都是些基本的线段树结构,但只有这些并不能做什么,就好比一个程序有

Kuangbin 带你飞-线段树专题 题解

HDU 1166 敌兵布阵 单调更新区间查询和 #include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #inc

非递归线段树专题

学习了自底向上的非递归线段树,深感精妙!! 大牛的博客:http://blog.csdn.net/zearot/article/details/48299459 张坤玮---统计的力量 The Union of k-Segments CodeForces - 612D 题意:求被覆盖k次及以上的点或者线段. 看到别人直接用扫描线写的,更方便一些. 不过拿来练习线段树也不错. 1 #include <bits/stdc++.h> 2 using namespace std; 3 const in

Vijos1448题解---线段树+括号法

描述 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:K=1,K=1,读入l.r表示在区间[l,r]中种上一种树,每次操作种的树的种类都不同K=2,读入l,r表示询问l~r之间能见到多少种树(l,r>0) 输入格式 第一行n,m表示道路总长为n,共有m个操作接下来m行为m个操作 输出格式 对于每个k=2输出一个答案 样例输入 5 4 1 1 3 2 2 5 1 2 4 2 3 5

线段树专题(一)

Acmer可怜啊,根本没有休息,昨天才刚刚完成了矩阵专题,今天又要开线段树专题了.唉,等我以后月薪15K的时候,我要好好享受人生......呃,扯远了.线段树是一个非常重要的数据结构,以前就学习过,但是没有系统的刷过难题,这次我决定将kuangbin先生的专题和NotOnlySuccess大神的专题一起刷掉.因为题目多又难,所以分成几个部分(最多三个把). 对于线段树的话,主要是理解它的树形结构吧,推荐和树状数组一起学习.似乎树状数组就是线段树的退化,树状数组节约了差不多一半的空间,但是必须满足

线段树专题(持续更新中...)

单点更新:最最基础的线段树,只更新叶子节点,然后把信息用PushUP(int r)这个函数更新上来 hdu1166 敌兵布阵 线段树功能:update:单点增减 query:区间求和 1 #include <iostream> 2 #include<cstring> 3 #include<stdio.h> 4 using namespace std; 5 #define M 50005 6 int sum[M<<2]; 7 void pushup(int r

线段树专题(不定期更新)

1.hdu 1166 敌兵布阵(★☆☆☆☆) 题意:有n个营地,每个营地初始各有若干人,每次询问[l,r]营地的总人数,或者对某个营地加上或减去若干人数. 思路:线段树单点更新,区间查询 1 //线段树单点更新,区间查询 2 #include<iostream> 3 using namespace std; 4 const int maxn = 50010; 5 int N; 6 int barracks[maxn]; 7 int Tree[4 * maxn]; 8 void Create(i