线段树学习总结

线段树用途:

用于区间修改与求和:

 区间修改:

 修改l到r之间的值 , 遍历线段树 , 若某个子节点l<=L && R<=r ,则在该节点上标记修改的值 , 访问该节点及他的子节点时再将标记下传;

 


线段树可持久化:

核心: 永远不修改节点上的值 , 只会新建节点 ;

实现:

 每当修改值的时候 , 新建一个根节点 , 将他与上一个版本的线段树中未修改的值相连 ,对于修改的值新建一个节点 , 当访问到新节点及他的子节点时再动态开点;

 


zkw非递归线段树:

建树:

 int t[N*2];

 for(int i=1;i<=n;i++) t[i+N]=a[i];

单点修改(将下标x上的值改为y):

 t[x+=N]=y;

 for(x>>=1;x;x>>=1)

 {

   t[x]=t[x<<1]+t[x<<1|1];

 }

区间求和:

 int ans=0;

 for(l+=N-1,r+=N;l^r^1;l>>=1,r>>=1)  // l^r^1用来判断左右节点的父节点是不是同一个节点

 {

   /* 如果当前区间的左端点在他父节点的左子节点上就要加上他的父节点的右子节点,相当于左端点包括了右字节点所包括的数*/

   if(!(l^1)) ans+=t[l^1];

   /* 如果当前区间的右端点在他父节点的右子节点上就要加上他的父节点的左子节点*/

   if(r^1) ans+=t[r^1];

  }

特点:

 不能标记下传; 

 可以用来代替堆优化Dijkstra;

 


带修改的二维区间求和:

建树:

 建立一棵范围为[1,n]的线段树,再在这棵线段树的每个节点上建立一棵范围为[1,m]的线段树;


题目:

【CF260E】 Dividing Kingdom (题目):

 9!暴力枚举状态 + 线段树可持久化判断当前状态对错;

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #include<iostream>
  5 #include<algorithm>
  6 using namespace std;
  7 
  8 const int N = 100010;
  9 
 10 int n;
 11 int a[9];
 12 int cntx, cnty;
 13 int x[N], y[N];
 14 int sum[N * 20], ls[N * 20], rs[N * 20], root[N], tot;
 15 vector<int> ins[N];
 16 
 17 struct Node
 18 {
 19     int x, y;
 20 }t[N];
 21 
 22 void update(int& q, int last, int l, int r, int v)
 23 {
 24     q = ++tot;
 25     ls[q] = ls[last];
 26     rs[q] = rs[last];
 27     sum[q] = sum[last] + 1;
 28 
 29     if(l == r) return;
 30     int mid = (l + r) >> 1;
 31     if (v <= mid) update(ls[q], ls[last], l, mid, v);
 32     else update(rs[q], rs[last], mid + 1, r, v);
 33 }
 34 
 35 int kth(int p, int q, int l, int r, int v) // 找第p版本线段树到第q版本线段树中差值为v的节点
 36 {
 37     if (l == r) return l;
 38 
 39     int s = sum[ls[q]] - sum[ls[p]];
 40     int mid = (l + r) >> 1;
 41     if (s >= v) return kth(ls[p], ls[q], l, mid, v);
 42     else return kth(rs[p], rs[q], mid + 1, r, v - s);
 43 }
 44 
 45 int query(int q, int l, int r, int L, int R) // 求区间和
 46 {
 47     if ((!q) || (L <= l && r <= R)) return sum[q];
 48 
 49     int res = 0;
 50     int mid = (l + r) >> 1;
 51     if (L <= mid) res += query(ls[q], l, mid, L, R);
 52     if (R > mid) res += query(rs[q], mid + 1, r, L, R);
 53     return res;
 54 }
 55 
 56 
 57 int S(int l1, int r1, int l2, int r2) // 求子矩阵 点[l1,l2] 到 点[r1,r2] 之间的点的数量
 58 {
 59     return query(root[r1], 1, cnty, l2, r2) - query(root[l1 - 1], 1, cnty, l2, r2);
 60 }
 61 
 62 bool solve() 
 63 {
 64     int l = 1, r = cntx, ans = 0; // 求在左边的那条竖线
 65     while (l <= r)
 66     {
 67         int mid = (l + r) >> 1;
 68         if (sum[root[mid]] >= a[0] + a[1] + a[2])
 69         {
 70             ans = mid;
 71             r = mid - 1;
 72         }
 73         else l = mid + 1;
 74     }
 75     if (ans == 0 || sum[root[ans]] != a[0] + a[1] + a[2]) return false; // 没找到这条线
 76     int p1 = ans;
 77 
 78     l = 1, r = cntx, ans = 0; // 求在右边的那条竖线
 79     while (l <= r)
 80     {
 81         int mid = (l + r) >> 1;
 82         if (sum[root[mid]] >= a[0] + a[1] + a[2] + a[3] + a[4] + a[5])
 83         {
 84             ans = mid;
 85             r = mid - 1;
 86         }
 87         else l = mid + 1;
 88     }
 89     if (ans == 0 || sum[root[ans]] != a[0] + a[1] + a[2] + a[3] + a[4] + a[5]) return false; // 没找到这条线
 90     int p2 = ans;
 91 
 92     int posx1 = kth(root[0], root[p1], 1, cnty, a[0]); // 找上面那条横线
 93     while (S(1, p1, 1, posx1) != a[0] || S(p1 + 1, p2, 1, posx1) != a[3] || S(p2 + 1, cntx, 1, posx1) != a[6])
 94     {
 95         if (S(1, p1, 1, posx1) != a[0]) return false; // 找不到
 96         ++posx1;
 97     }
 98 
 99     int posx2 = kth(root[0], root[p1], 1, cnty, a[0] + a[1]); // 找下面那条横线
100     while (S(1, p1, posx1+1, posx2) != a[1] || S(p1 + 1, p2, posx1 + 1, posx2) != a[4] || S(p2 + 1, cntx, posx1 + 1, posx2) != a[7])
101     {
102         if (S(1, p1, posx1 + 1, posx2) != a[1]) return false; // 找不到
103         ++posx2;
104     }
105 
106     printf("%.10lf %.10lf \n%.10lf %.10lf", x[p1] + 0.5, x[p2] + 0.5, y[posx1] + 0.5, y[posx2] + 0.5);
107     return true;
108 }
109 
110 bool com(Node a, Node b)
111 {
112     return a.x == b.x ? a.y < b.y : a.x < b.x;
113 }
114 
115 int main()
116 {
117     scanf("%d", &n);
118     for (int i = 1; i <= n; i++)
119     {
120         scanf("%d%d", &t[i].x, &t[i].y);
121         x[++cntx] = t[i].x;
122         y[++cnty] = t[i].y;
123     }
124     for (int i = 0; i < 9; i++) scanf("%d", &a[i]);
125 
126     sort(x + 1, x + 1 + cntx);
127     cntx = unique(x + 1, x + 1 + cntx) - (x + 1);
128     sort(y + 1, y + 1 + cnty);
129     cnty = unique(y + 1, y + 1 + cnty) - (y + 1);
130     sort(t + 1, t + 1 + n, com);
131 
132     for (int i = 1; i <= n; i++) // 哈希
133     {
134         t[i].x = lower_bound(x + 1, x + cntx + 1, t[i].x) - x;
135         t[i].y = lower_bound(y + 1, y + cnty + 1, t[i].y) - y;
136         ins[t[i].x].push_back(t[i].y);
137     }
138 
139     for (int i = 1; i <= cntx; i++) // 建可持久化线段树
140     {
141         root[i] = root[i - 1];
142         for (int j = 0; j < ins[i].size(); j++)
143         {
144             update(root[i], root[i], 1, cnty, ins[i][j]);
145         }
146     }
147 
148     int loop = 362880;
149     while (loop--)
150     {
151         next_permutation(a, a + 9); // 全排列
152         if (solve()) return 0;
153     }
154 
155     puts("-1");
156 }
View Code

 


 

 【CF266E】 More Queries to Array... (题目): 

  将  后面的 ( i-l+1)k 通过二项式定理  

  拆开变成 

     然后再将式子  变成

  预处理出C(i,j), 记录 i的前缀和 , 再通过线段树存储, 最后求解

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 const int N = 100010, mod = 1000000007;
  8 
  9 int n, m;
 10 int t[N * 4][6], lazy[N * 4]; // t[i][j]表示子节点i在j次方下的线段树  lazy懒标记
 11 int power[6][N], a[N];
 12 int C[6][6];
 13 
 14 struct Node
 15 {
 16     int d[6];
 17 };
 18 
 19 signed mo(int x, int y)
 20 {
 21     return x + y >= mod ? x + y - mod : x + y;
 22 }
 23 
 24 void init()
 25 {
 26     C[0][0] = 1;
 27     for (int i = 1; i < 6; i++)
 28     {
 29         C[i][0] = C[i][i] = 1;
 30         for (int j = 1; j < i; j++)
 31         {
 32             C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
 33         }
 34     }
 35 
 36     for (int i = 0; i < N; i++) power[0][i] = 1;
 37 
 38     for (int j = 1; j < 6; j++) // 求i的j次方
 39     {
 40         for (int i = 1; i < N; i++)
 41         {
 42             power[j][i] = 1ll * power[j - 1][i] * i % mod;
 43         }
 44     }
 45 
 46     for (int j = 0; j < 6; j++)  // 求次方的前缀和
 47     {
 48         for (int i = 1; i < N; i++)
 49         {
 50             power[j][i] = mo(power[j][i], power[j][i - 1]);
 51         }
 52     }
 53 }
 54 
 55 int get(int q, int l, int r)
 56 {
 57     return mo(power[q][r], mod - power[q][l - 1]);
 58 }
 59 
 60 void pushup(int q)
 61 {
 62     for (int i = 0; i < 6; i++)
 63     {
 64         t[q][i] = mo(t[q << 1][i], t[q << 1 | 1][i]);
 65     }
 66 }
 67 
 68 void pushdown(int q, int l, int mid, int r)
 69 {
 70     if (~lazy[q])
 71     {
 72         lazy[q << 1] = lazy[q << 1 | 1] = lazy[q];
 73 
 74         for (int j = 0; j < 6; j++)
 75         {
 76             t[q << 1][j] = 1ll * lazy[q] * get(j, l, mid) % mod;
 77             t[q << 1 | 1][j] = 1ll * lazy[q] * get(j, mid + 1, r) % mod;
 78         }
 79         lazy[q] = -1;
 80     }
 81 }
 82 
 83 void build(int q, int l, int r)
 84 {
 85     lazy[q] = -1;
 86     if (l == r)
 87     {
 88         for (int j = 0; j < 6; j++)
 89         {
 90             t[q][j] = 1ll * a[l] * get(j, l, l) % mod;
 91         }
 92         return;
 93     }
 94 
 95     int mid = (l + r) >> 1;
 96     build(q << 1, l, mid);
 97     build(q << 1 | 1, mid + 1, r);
 98     pushup(q);
 99 }
100 
101 void update(int q, int l, int r, int L, int R, int x)
102 {
103     if (L == l && R == r)
104     {
105         lazy[q] = x;
106         for (int i = 0; i < 6; i++)
107         {
108             t[q][i] = 1ll * x * get(i, l, r) % mod;
109         }
110         return;
111     }
112 
113     int mid = (l + r) >> 1;
114     pushdown(q, l, mid, r);
115 
116     if (R <= mid) update(q << 1, l, mid, L, R, x);
117     else if (L > mid) update(q << 1 | 1, mid + 1, r, L, R, x);
118     else
119     {
120         update(q << 1, l, mid, L, mid, x);
121         update(q << 1 | 1, mid + 1, r, mid + 1, R, x);
122     }
123     pushup(q);
124 }
125 
126 Node query(int q, int l, int r, int L, int R)
127 {
128     Node res;
129     if (l == L && r == R)
130     {
131         for (int i = 0; i < 6; i++)
132         {
133             res.d[i] = t[q][i];
134         }
135         return res;
136     }
137 
138     Node resl, resr;
139     int mid = (l + r) >> 1;
140     pushdown(q, l, mid, r);
141 
142     for (int j = 0; j < 6; j++) resl.d[j] = resr.d[j] = 0;
143 
144     if (R <= mid) resl = query(q << 1, l, mid, L, R);
145     else if (L > mid) resr = query(q << 1 | 1, mid + 1, r, L, R);
146     else
147     {
148         resl = query(q << 1, l, mid, L, mid);
149         resr = query(q << 1 | 1, mid + 1, r, mid + 1, R);
150     }
151 
152     for (int i = 0; i < 6; i++)
153     {
154         resl.d[i] = mo(resl.d[i], resr.d[i]);
155     }
156     return resl;
157 }
158 
159 int main()
160 {
161     init();
162 
163     scanf("%d%d", &n, &m);
164     for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
165 
166     build(1, 1, n);
167     while (m--)
168     {
169         char c;
170         while (scanf("%c", &c), c != '?' && c != '=');
171 
172         if (c == '=')
173         {
174             int l, r, x;
175             scanf("%d%d%d", &l, &r, &x);
176             update(1, 1, n, l, r, x);
177         }
178         else
179         {
180             int l, r, k;
181             scanf("%d%d%d", &l, &r, &k);
182             Node u = query(1, 1, n, l, r);
183 
184             int res, ans = 0;
185             for (int j = 0; j <= k; j++)
186             {
187                 if (l > 1) res = get(k - j, l - 1, l - 1);
188                 else res = power[k - j][l - 1];
189                 if (((k ^ j) & 1) && res) res = mod - res;
190                 ans = mo(ans, 1ll * res * C[k][j] % mod * u.d[j] % mod);
191             }
192             printf("%d\n", ans);
193         }
194 
195     }
196 }
View Code

【CF323C】 Two permutations (题目):

  把两个序列想象成矩阵,第一个序列为行,第二个序列为列,a[i]=b[j]=x表示x这个点在矩阵[j,i]上,再用主席树(可持久化线段树)求子区间和;

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int N = 1000010, M = 40000010;
 8 
 9 int n;
10 int id[N], a[N];
11 int root[N * 4], tot;
12 int ls[M], rs[M], sum[M];
13 
14 void update(int& q, int k, int l, int r, int v)
15 {
16     q = ++tot;
17     ls[q] = ls[k];
18     rs[q] = rs[k];
19     sum[q] = sum[k] + 1;
20 
21     if (l == r) return;
22     
23     int mid = (l + r) >> 1;
24     if (v <= mid) update(ls[q], ls[k], l, mid, v);
25     else update(rs[q], rs[k], mid + 1, r, v);
26 }
27 
28 int f(int a,int x)
29 {
30     return ((a - 1 + x) % n) + 1;
31 }
32 
33 int query(int q, int l, int r, int L, int R)
34 {
35     if (l == L && r == R)
36     {
37         return sum[q];
38     }
39 
40     int mid = (l + r) >> 1;
41     if (R <= mid) return query(ls[q], l, mid, L, R);
42     else if (L > mid) return query(rs[q], mid + 1, r, L, R);
43     else return query(ls[q], l, mid, L, mid) + query(rs[q], mid + 1, r, mid + 1, R);
44 }
45 
46 int main()
47 {
48     scanf("%d", &n);
49     for (int i = 1; i <= n; i++)
50     {
51         int c;
52         scanf("%d", &c);
53         id[c] = i;
54     }
55     for (int i = 1; i <= n; i++)
56     {
57         int c;
58         scanf("%d", &c);
59         a[i] = id[c];
60     }
61 
62     for (int i = 1; i <= n; i++)
63     {
64         update(root[i], root[i - 1], 1, n, a[i]);
65     }
66 
67     int m, ans = 0;
68     scanf("%d", &m);
69     while (m--)
70     {
71         int a, b, c, d;
72         scanf("%d%d%d%d", &a, &b, &c, &d);
73         int l1, r1, l2, r2;
74         l1 = min(f(a, ans), f(b, ans)), r1 = max(f(a, ans), f(b, ans));
75         l2 = min(f(c, ans), f(d, ans)), r2 = max(f(c, ans), f(d, ans));
76 
77         printf("%d\n", ans = query(root[r2], 1, n, l1, r1) - query(root[l2 - 1], 1, n, l1, r1));
78         ans++;
79     }
80 }
View Code

 【CF240F】TorCoder(题目):

  建立26个线段树分别代表a~z,当要执行区间【l,r】时,枚举每一个字母在这个区间中的数量,若区间长度为奇,则要有一个奇数个数的字母;区间长度为偶,则不能有奇数个数的字母。

  判断是否要执行这个区间后,从a枚举到z将字母放入其中

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 typedef long long ll;
  8 
  9 const int INF = 0x3f3f3f3f;
 10 
 11 #define lc(a) ((a) << 1)
 12 #define rc(a) ((a) << 1 | 1)
 13 
 14 int cnt[30];
 15 char s[100010];
 16 
 17 struct tree
 18 {
 19     int l;
 20     int r;
 21     int sum[30];
 22     int lazy;
 23 
 24     void clear() 
 25     {
 26         memset(sum, 0, sizeof(sum));
 27     }
 28 };
 29 
 30 tree operator + (tree a, tree b)
 31 {
 32     if (a.l == -1) return b;
 33     if (b.l == -1) return a;
 34 
 35     tree ret;
 36     ret.l = a.l;
 37     ret.r = b.r;
 38     for (int i = 0; i < 26; i++) ret.sum[i] = a.sum[i] + b.sum[i];
 39     return ret;
 40 }
 41 
 42 struct Tree 
 43 {
 44     tree t[800010];
 45 
 46     void push_up(int q) 
 47     {
 48         for (int i = 0; i < 26; i++) t[q].sum[i] = t[lc(q)].sum[i] + t[rc(q)].sum[i];
 49     }
 50 
 51     void push_down(int q) 
 52     {
 53         if (t[q].lazy != -1)
 54         {
 55             t[lc(q)].clear();
 56             t[rc(q)].clear();
 57             t[lc(q)].sum[t[q].lazy] = t[lc(q)].r - t[lc(q)].l + 1;
 58             t[rc(q)].sum[t[q].lazy] = t[rc(q)].r - t[rc(q)].l + 1;
 59             t[lc(q)].lazy = t[rc(q)].lazy = t[q].lazy;
 60         }
 61         t[q].lazy = -1;
 62     }
 63 
 64     void build(int q, int l, int r) 
 65     {
 66         t[q].lazy = -1;
 67         t[q].l = l;
 68         t[q].r = r;
 69 
 70         if (l == r)
 71         {
 72             t[q].clear();
 73             t[q].sum[s[l] - 'a'] = 1;
 74             return;
 75         }
 76 
 77         int mid = (l + r) >> 1;
 78         build(lc(q), l, mid);
 79         build(rc(q), mid + 1, r);
 80         push_up(q);
 81     }
 82 
 83     void query(int q, int l, int r)
 84     {
 85         tree nul;
 86         nul.l = -1;
 87         if (t[q].l > r || t[q].r < l)  return;
 88 
 89         push_down(q);
 90         if (t[q].l >= l && t[q].r <= r) 
 91         {
 92             for (int i = 0; i < 26; i++)  cnt[i] += t[q].sum[i];
 93             return;
 94         }
 95         query(lc(q), l, r);
 96         query(rc(q), l, r);
 97     }
 98 
 99     void update(int q, int l, int r, int c)
100     {
101         if (t[q].l > r || t[q].r < l)  return;
102 
103         if (t[q].l >= l && t[q].r <= r) 
104         {
105             t[q].clear();
106             t[q].sum[c] = t[q].r - t[q].l + 1;
107             t[q].lazy = c;
108             return;
109         }
110 
111         push_down(q);
112         update(lc(q), l, r, c);
113         update(rc(q), l, r, c);
114         push_up(q);
115     }
116 
117     void print(int q) 
118     {
119         if (t[q].l == t[q].r) 
120         {
121             for (int i = 0; i < 26; i++)
122             {
123                 if (t[q].sum[i]) putchar('a' + i);
124             }
125             return;
126         }
127 
128         push_down(q);
129         print(lc(q));
130         print(rc(q));
131     }
132 }t;
133 
134 int main()
135 {
136     freopen("input.txt", "r", stdin);
137     freopen("output.txt", "w", stdout);
138 
139     int n, m;
140     scanf("%d%d", &n, &m);
141     scanf("%s", s + 1);
142 
143     t.build(1, 1, n);
144     while (m--)
145     {
146         int l, r;
147         scanf("%d%d", &l, &r);
148 
149         memset(cnt, 0, sizeof(cnt));
150         t.query(1, l, r);
151         if ((r - l + 1) & 1)
152         {
153             int cs = 0, num;
154             for (int i = 0; i < 26; i++)
155             {
156                 if (cnt[i] & 1)
157                 {
158                     cs++;
159                     num = i;
160                 }
161             }
162                 
163             if (cs == 1) 
164             {
165                 int mid = (l + r) >> 1;
166                 t.update(1, mid, mid, num);
167                 int cc = 0;
168                 for (int i = 0; i < 26; i++)
169                 {
170                     if (cnt[i] <= 1) continue;
171 
172                     int c2 = cc + (cnt[i] >> 1);
173                     t.update(1, l + cc, l + c2 - 1, i);
174                     t.update(1, r - c2 + 1, r - cc, i);
175                     cc = c2;
176                 }
177             }
178         }
179         else
180         {
181             int pd = 0, num = -1;
182 
183             for (int i = 0; i < 26; i++)
184             {
185                 if (cnt[i] & 1)
186                 {
187                     pd++;
188                     num = i;
189                 }
190             }
191 
192             if (pd == 0)
193             {
194                 int c = 0;
195                 for (int i = 0; i < 26; i++) 
196                 {
197                     if (cnt[i] == 0)  continue;
198 
199                     int c2 = c + (cnt[i] >> 1);
200                     t.update(1, l + c, l + c2 - 1, i);
201                     t.update(1, r - c2 + 1, r - c, i);
202                     c = c2;
203                 }
204             }
205         }
206     }
207     t.print(1);
208 }
View Code

【SHOI2008】堵塞的交通 (题目):

  线段树记录该子节点区间四个顶点的联通情况

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 const int maxn = 400010;
  8 
  9 #define lson o<<1,l,mid
 10 #define rson o<<1|1,mid+1,r
 11 
 12 struct Node
 13 {
 14     int lft, rig;
 15     bool l, r, u, d, p, q;
 16 }seg[maxn];
 17 
 18 int n;
 19 bool conn[maxn][2];
 20 
 21 void pushup(Node& x, Node l, Node r)
 22 {
 23     x.lft = l.lft;
 24     x.rig = r.rig;
 25 
 26     x.l = l.l | (l.u & conn[l.rig][0] & r.l & conn[l.rig][1] & l.d);
 27     x.r = r.r | (r.u & conn[l.rig][0] & l.r & conn[l.rig][1] & r.d);
 28 
 29     x.u = (l.u & conn[l.rig][0] & r.u) | (l.p & conn[l.rig][1] & r.q);
 30     x.d = (l.d & conn[l.rig][1] & r.d) | (l.q & conn[l.rig][0] & r.p);
 31 
 32     x.p = (l.u & conn[l.rig][0] & r.p) | (l.p & conn[l.rig][1] & r.d);
 33     x.q = (l.d & conn[l.rig][1] & r.q) | (l.q & conn[l.rig][0] & r.u);
 34 }
 35 
 36 void build(int o, int l, int r)
 37 {
 38     if (l == r)
 39     {
 40         seg[o].lft = seg[o].rig = l;    
 41         seg[o].u = seg[o].d = 1;     //左右联通
 42         return;
 43     }
 44 
 45     int mid = (l + r) >> 1;
 46     build(lson);
 47     build(rson);
 48     pushup(seg[o], seg[o << 1], seg[o << 1 | 1]);
 49 }
 50 
 51 void update1(int o, int l, int r, int p, int row, bool val) //同行修改
 52 {    
 53     int mid = (l + r) >> 1;
 54     if (mid == p)
 55     {
 56         conn[mid][row] = val;
 57         pushup(seg[o], seg[o << 1], seg[o << 1 | 1]);
 58         return;
 59     }
 60 
 61     if (mid >= p) update1(lson, p, row, val);
 62     else update1(rson, p, row, val);
 63     pushup(seg[o], seg[o << 1], seg[o << 1 | 1]);
 64 }
 65 
 66 void update2(int o, int l, int r, int p, bool val)     //不同行修改,第p列
 67 {
 68     if (l == r) 
 69     {
 70         seg[o].l = seg[o].r = seg[o].p = seg[o].q = val;
 71         return;
 72     }
 73 
 74     int mid = (l + r) >> 1;
 75     if (mid >= p) update2(lson, p, val);
 76     else update2(rson, p, val);
 77     pushup(seg[o], seg[o << 1], seg[o << 1 | 1]);
 78 }
 79 
 80 Node query(int o, int l, int r, int ql, int qr)
 81 {    
 82     if (l >= ql && r <= qr) return seg[o];
 83 
 84     int mid = (l + r) >> 1;
 85     if (mid < ql) return query(rson, ql, qr);
 86     if (mid >= qr) return query(lson, ql, qr);
 87 
 88     Node ans;
 89     pushup(ans, query(lson, ql, qr), query(rson, ql, qr));
 90     return ans;
 91 }
 92 
 93 int main() 
 94 {
 95     scanf("%d", &n);
 96 
 97     char op[10];
 98     build(1, 1, n);
 99     while (scanf("%s", op) , op[0] != 'E')
100     {
101         int a, b, c, d;
102         scanf("%d%d%d%d", &a, &b, &c, &d);
103 
104         if (op[0] == 'C') //删边
105         {
106             if (a == c) update1(1, 1, n, min(b, d), a - 1, 0);    //同一行
107             else update2(1, 1, n, b, 0);    //不同行
108         }
109 
110         if (op[0] == 'O')    //加边
111         {
112             if (a == c) update1(1, 1, n, min(b, d), a - 1, 1);
113             else update2(1, 1, n, b, 1);
114         }
115 
116         if (op[0] == 'A')    //询问
117         {
118             if (b > d) swap(a, c), swap(b, d);
119             Node ans1 = query(1, 1, n, b, d), ans2 = query(1, 1, n, 1, b), ans3 = query(1, 1, n, d, n);
120             bool flag = false;
121             if (a == 1)
122             {
123                 if (c == 1) //左上,右上
124                 {
125                     if (ans1.u) flag = true;
126                     if (ans2.r & ans1.d & ans3.l) flag = true;
127                 }
128                 else //左上,右下
129                 {
130                     if (ans1.p) flag = true;
131                     if (ans2.r & ans1.d) flag = true;
132                     if (ans3.l & ans1.u) flag = true;
133                 }
134             }
135             else
136             {
137                 if (c == 1) //左下,右上
138                 {
139                     if (ans1.q) flag = true;
140                     if (ans2.r & ans1.u) flag = true;
141                     if (ans3.l & ans1.d) flag = true;
142                 }
143                 else //左下,右下
144                 {
145                     if (ans1.d) flag = true;
146                     if (ans2.r & ans1.u & ans3.l) flag = true;
147                 }
148             }
149             puts(flag ? "Y" : "N");
150         }
151     }
152 }
View Code

 【THUPC 2017】天天爱射击 (题目):

  把子弹坐标当做版本,时间当做值,对于每一个木板,如果它能被打碎,则在木板的区间内找到的第s个点就是打碎它的子弹;

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 const int N = 200010, M=8000010;
 9 
10 int n, m;
11 int root[N], tot;
12 int ls[M], rs[M], sum[M];
13 int res[N];
14 vector<int> t[N];
15 
16 struct Node
17 {
18     int l, r, s;
19 }a[N];
20 
21 void update(int& q, int l, int r, int x)
22 {
23     sum[++tot] = sum[q] + 1;
24     ls[tot] = ls[q];
25     rs[tot] = rs[q];
26     q = tot;
27 
28     if (l == r) return;
29 
30     int mid = (l + r) >> 1;
31     if (x <= mid) update(ls[q], l, mid, x);
32     else update(rs[q], mid + 1, r, x);
33 }
34 
35 int query(int lt, int rt, int l, int r, int k)
36 {
37     if (l == r) return l;
38 
39     int s = sum[ls[rt]] - sum[ls[lt]];
40     int mid = (l + r) >> 1;
41     if (k <= s) return query(ls[lt], ls[rt], l, mid, k);
42     else return query(rs[lt], rs[rt], mid + 1, r, k - s);
43 }
44 
45 int main()
46 {
47     scanf("%d%d", &n, &m);
48 
49     int all = 0;
50     for (int i = 1; i <= n; i++)
51     {
52         scanf("%d%d%d", &a[i].l, &a[i].r, &a[i].s);
53         all = max(all, a[i].r);
54     }
55 
56     for (int i = 1; i <= m; i++)
57     {
58         int x;
59         scanf("%d", &x);
60         t[x].push_back(i);
61         all = max(all, x);
62     }
63 
64     for (int i = 1; i <= all; i++)
65     {
66         root[i] = root[i - 1];
67         if (!t[i].empty())
68         {
69             for (int j = 0; j < t[i].size(); ++j) update(root[i], 1, m, t[i][j]);
70         }
71     }
72 
73     for (int i = 1; i <= n; i++)
74     {
75         if (sum[root[a[i].r]] - sum[root[a[i].l - 1]] < a[i].s) continue;
76         int rp = query(root[a[i].l - 1], root[a[i].r], 1, m, a[i].s);
77         ++res[rp];
78     }
79     for (int i = 1; i <= m; i++) printf("%d\n", res[i]);
80 }
View Code

【CF316E3】 Summer Homework题目):

  引理:

  fi = fkfi-k + fk-1fi-k-1  (1≤k<i)

  证明:

  当i≤1时结论成立

  当i>1时,假设fi-1和fi-2满足引理,选取一个k(1≤k<i-2)

  fi=fi-1+fi-2

  fi=fkfi-1-k+fk-1fi-1-k-1+fkfi-2-k+fkfi-2-k-1

  fi = fkfi-k + fk-1fi-k-1

  

  之后再s1表示a1*f0+a2*f1+a3*f2 , s2表示a1*f1+a2*f2+a3*f3

  若要把这个序列的斐波那契系数向右移动x个单位,设结果为S,则

  S=S1*fx-2+S2*fx-1

 

  在线段树上维护S1和S2,之后执行pushup操作时,将右子节点的斐波那契系数向右移动x位(左子节点的长度),就可以合并出他们的父节点了

 

  执行区间修改时,假设该区间都加上了x,则相当于整个区间加上了x倍的一段斐波那契前缀和,预处理前缀和即可

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 typedef long long LL;
  8 
  9 const LL N = 2e5 + 10, mod = 1e9;
 10 
 11 LL n, m;
 12 LL f[N], sum[N];
 13 LL s1[N * 4], s2[N * 4], lazy[N * 4];
 14 
 15 void add(LL q, LL l, LL r, LL x)
 16 {
 17     lazy[q] = (lazy[q] + x) % mod;
 18     s1[q] = (s1[q] + sum[r - l] * x % mod) % mod;
 19     s2[q] = (s2[q] + (sum[r - l + 1] + mod - 1) % mod * x % mod) % mod;
 20 }
 21 
 22 LL calc(LL q, LL x)
 23 {
 24     if (x == 0) return s1[q];
 25     else if (x == 1) return s2[q];
 26     else return (s1[q] * f[x - 2] % mod + s2[q] * f[x - 1] % mod) % mod;
 27 }
 28 
 29 void pushup(LL q, LL l, LL r)
 30 {
 31     LL mid = (l + r) >> 1;
 32     s1[q] = (s1[q << 1] + calc(q << 1 | 1, mid - l + 1)) % mod;
 33     s2[q] = (s2[q << 1] + calc(q << 1 | 1, mid - l + 2)) % mod;
 34 }
 35 
 36 void pushdown(LL q, LL l, LL r)
 37 {
 38     if (!lazy[q]) return;
 39 
 40     LL mid = (l + r) >> 1;
 41     add(q << 1, l, mid, lazy[q]);
 42     add(q << 1 | 1, mid + 1, r, lazy[q]);
 43     lazy[q] = 0;
 44 }
 45 
 46 void update(LL q, LL l, LL r, LL L, LL R, LL x)
 47 {
 48     if (L <= l && r <= R)
 49     {
 50         add(q, l, r, x);
 51         return;
 52     }
 53 
 54     pushdown(q, l, r);
 55     LL mid = (l + r) >> 1;
 56     if (L <= mid) update(q << 1, l, mid, L, R, x);
 57     if (mid < R) update(q << 1 | 1, mid + 1, r, L, R, x);
 58     pushup(q, l, r);
 59 }
 60 
 61 void modify(LL q, LL l, LL r, LL x, LL v)
 62 {
 63     if (l == r)
 64     {
 65         s1[q] = s2[q] = v;
 66         return;
 67     }
 68 
 69     pushdown(q, l, r);
 70     LL mid = (l + r) >> 1;
 71     if (x <= mid) modify(q << 1, l, mid, x, v);
 72     else modify(q << 1 | 1, mid + 1, r, x, v);
 73     pushup(q, l, r);
 74 }
 75 
 76 LL query(LL q, LL l, LL r, LL L, LL R)
 77 {
 78     if (L <= l && r <= R)
 79     {
 80         return calc(q, l - L);
 81     }
 82 
 83     pushdown(q, l, r);
 84     LL res = 0;
 85     LL mid = (l + r) >> 1;
 86     if (L <= mid) res = query(q << 1, l, mid, L, R);
 87     if (mid < R) res = (res + query(q << 1 | 1, mid + 1, r, L, R)) % mod;
 88     return res;
 89 }
 90 
 91 void init()
 92 {
 93     f[0] = f[1] = 1;
 94     sum[0] = 1, sum[1] = 2;
 95     for (int i = 2; i < N; i++)
 96     {
 97         f[i] = (f[i - 1] + f[i - 2]) % mod;
 98         sum[i] = (sum[i - 1] + f[i]) % mod;
 99     }
100 }
101 
102 int main()
103 {
104     init();
105 
106     scanf("%lld%lld", &n, &m);
107     for (int i = 1; i <= n; i++)
108     {
109         LL x;
110         scanf("%lld", &x);
111         modify(1, 1, n, i, x);
112     }
113 
114     while (m--)
115     {
116         LL c;
117         scanf("%lld", &c);
118         switch (c)
119         {
120         case 1:
121         {
122             LL i, x;
123             scanf("%lld%lld", &i, &x);
124             modify(1, 1, n, i, x);
125             break;
126         }
127         case 2:
128         {
129             LL l, r;
130             scanf("%lld%lld", &l, &r);
131             printf("%lld\n", query(1, 1, n, l, r) % mod);
132             break;
133         }
134         case 3:
135         {
136             LL l, r, x;
137             scanf("%lld%lld%lld", &l, &r, &x);
138             update(1, 1, n, l, r, x);
139             break;
140         }
141         }
142     }
143 }
View Code

 


【NOI2017】 整数 (题目):

  将加和减分开统计,比较后缀大小,暴力找到下一个不等的位置。用set维护不等的位置,每次查找以下。

 

  将数字每16个分成一位,每次修改是修改块内是为不同的数字个数,用set维护每一块内是否有不同的数字,每次询问我们先在当前块中查询,如果没有则在上一个有不同数字的块中查找。

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<set>
  4 #include<iostream>
  5 #include<algorithm>
  6 using namespace std;
  7 
  8 const int N = 30000005, L = 200005;
  9 
 10 char str[L];
 11 char *S = str, * T = str;
 12 
 13 char gc() 
 14 {
 15     if (S == T) 
 16     {
 17         T = (S = str) + fread(str, 1, L, stdin);
 18         if (S == T) return EOF;
 19     }
 20     return *S++;
 21 }
 22 
 23 int read() 
 24 {
 25     int x = 0, f = 1;
 26     char c = gc();
 27     for (; c < '0' || c>'9'; c = gc()) if (c == '-') f = -1;
 28     for (; c >= '0' && c <= '9'; c = gc()) x = (x << 1) + (x << 3) + c - 48;
 29     return x * f;
 30 }
 31 
 32 int n, x, y;
 33 bool fl, a[N], b[N];
 34 
 35 struct cmp 
 36 {
 37     bool operator ()(const int& x, const int& y)
 38     {
 39         return x > y;
 40     }
 41 };
 42 
 43 struct Node 
 44 {
 45     int cnt[2000005];
 46     set<int, cmp> S;
 47 
 48     Node()
 49     {
 50         S.insert(-1);
 51         memset(cnt, 0, sizeof(cnt));
 52     }
 53 
 54     void insert(int x)
 55     {
 56         x += 16;
 57         if (!cnt[x >> 4]) S.insert(x >> 4);
 58         cnt[x >> 4]++;
 59     }
 60 
 61     void erase(int x) 
 62     {
 63         x += 16;
 64         cnt[x >> 4]--;
 65         if (!cnt[x >> 4]) S.erase(x >> 4);
 66     }
 67 
 68     int query(int x)
 69     {
 70         if (x < 0) return -2;
 71         x += 16;
 72         for (int i = x; i >= ((x >> 4) << 4) && i >= 16; i--)
 73         {
 74             if (a[i - 16] ^ b[i - 16]) return i - 16;
 75         }
 76         int y = *S.lower_bound((x >> 4) - 1);
 77         if (y == -1) return -2;
 78         for (int i = (y << 4) + 15; i >= (y << 4) && i >= 16; i--)
 79         {
 80             if (a[i - 16] ^ b[i - 16]) return i - 16;
 81         }
 82         return -2;
 83     }
 84 }tree;
 85 
 86 void add()
 87 {
 88     bool tg = 1;
 89     for (int i = y; i <= n * 30 && ((tg ^ 1) || x); i++, x /= 2)
 90     {
 91         if ((tg ^ 1) ^ (x & 1)) 
 92         {
 93             if (a[i] ^ b[i]) tree.erase(i);
 94             else tree.insert(i);
 95             if (fl) tg = (a[i] ^= 1);
 96             else tg = (b[i] ^= 1);
 97         }
 98         else
 99             tg = ((tg ^ 1) && (x & 1)) ^ 1;
100     }
101 }
102 
103 int main() 
104 {
105     n = read(); 
106     read(), read(), read();
107 
108     tree.insert(-2);
109     for (int i = 1; i <= n; i++)
110     {
111         if (read() == 1)
112         {
113             x = read(); y = read();
114             fl = (x > 0); x = x < 0 ? -x : x;
115             add();
116         }
117         else
118         {
119             x = read(); y = tree.query(x - 1);
120             putchar((a[x] ^ b[x] ^ (y != -2 && !a[y])) + '0'); 
121             puts("");
122         }
123     }
124 }
View Code

 【NOI2016】区间(题目):

  将区间按长度排序,从小到大枚举,通过线段树判断某个点是否被覆盖m次

 

 

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<stack>
  7 #include<queue>
  8 using namespace std;
  9 
 10 const int N = 501000;
 11 const int INF = 1e9;
 12 
 13 int n, m;
 14 int res, cur = 0;
 15 int L[N * 2], R[N * 2];
 16 int t[N * 8], sum[N * 8];
 17 
 18 struct Point
 19 {
 20     int val, ord;
 21 }p[N * 4];
 22 
 23 struct Node 
 24 {
 25     int len, ord;
 26 }a[N * 4];
 27 
 28 bool cmp1(Point x1, Point x2) 
 29 {
 30     if (x1.val < x2.val)return true;
 31     return false;
 32 }
 33 
 34 bool cmp2(Node x1, Node x2)
 35 {
 36     if (x1.len < x2.len)return true;
 37     return false;
 38 }
 39 
 40 void pushdown(int q, int l, int r)
 41 {
 42     if (!sum[q])return;
 43     int ls = q << 1, rs = q << 1 | 1;
 44     t[ls] += sum[q];
 45     t[rs] += sum[q];
 46     sum[ls] += sum[q];
 47     sum[rs] += sum[q];
 48     sum[q] = 0;
 49     return;
 50 }
 51 
 52 void update(int q, int l, int r, int x, int y, int val)
 53 {
 54     if (x > r || y < l) return;
 55     if (x <= l && y >= r) 
 56     {
 57         t[q] += val;
 58         sum[q] += val;
 59         return;
 60     }
 61     int mid = (l + r) / 2;
 62 
 63     pushdown(q, l, r);
 64     update(q << 1, l, mid, x, y, val);
 65     update(q << 1 | 1, mid + 1, r, x, y, val);
 66     t[q] = max(t[q << 1], t[q << 1 | 1]);
 67 }
 68 
 69 int main()
 70 {
 71     scanf("%d%d", &n, &m);
 72     for (int i = 1; i <= n; i++) 
 73     {
 74         int u, v;
 75         scanf("%d%d", &u, &v);
 76         a[i].len = v - u;
 77         a[i].ord = i;
 78 
 79         cur++;
 80         p[cur].val = u;
 81         p[cur].ord = i;
 82 
 83         cur++;
 84         p[cur].val = v;
 85         p[cur].ord = i;
 86     }
 87 
 88     sort(p + 1, p + cur + 1, cmp1);
 89     int num = 0;
 90     p[0].val = -1;
 91     for (int i = 1; i <= cur; i++) 
 92     {
 93         if (p[i].val != p[i - 1].val) num++;
 94 
 95         int u = p[i].ord;
 96         if (!L[u]) L[u] = num;
 97         else R[u] = num;
 98     }
 99 
100     res = num;
101     sort(a + 1, a + n + 1, cmp2);
102     int ans = INF, le = 0, ri = 0;
103     while (true) 
104     {
105         while (t[1] < m && ri <= n) 
106         {
107             ri++;
108             int u = a[ri].ord, v = L[u], w = R[u];
109             update(1, 1, res, v, w, 1);
110         }
111 
112         if (t[1] < m)break;
113         while (t[1] >= m && le <= n) 
114         {
115             le++;
116             int u = a[le].ord, v = L[u], w = R[u];
117             update(1, 1, res, v, w, -1);
118         }
119         ans = min(ans, a[ri].len - a[le].len);
120     }
121 
122     if (ans == INF) printf("-1\n");
123     else printf("%d\n", ans);
124 }
View Code

  Preprefix sum(题目):

  因为 所以 SSi =拆开化简为 SSi =  SS ,用线段树维护aj和aj*j两个值即可

 

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 typedef long long LL;
 8 typedef pair<LL, LL> PLL;
 9 
10 const int N = 100010;
11 
12 int n, m;
13 struct Node
14 {
15     long long s1, s2;
16 }t[N*4];
17 
18 PLL add(PLL a, PLL b)
19 {
20     return make_pair(a.first + b.first, a.second + b.second);
21 }
22 
23 void pushup(int q, int l, int r)
24 {
25     t[q].s1 = t[q << 1].s1 + t[q << 1 | 1].s1;
26     t[q].s2 = t[q << 1].s2 + t[q << 1 | 1].s2;
27 }
28 
29 void modify(int q, int l, int r, int x, int v)
30 {
31     if (l == r)
32     {
33         t[q].s1 = (LL) v;
34         t[q].s2 = (LL) v * x;
35         return;
36     }
37 
38     int mid = (l + r) >> 1;
39     if (x <= mid) modify(q << 1, l, mid, x, v);
40     else if (x > mid) modify(q << 1 | 1, mid + 1, r, x, v);
41     pushup(q, l, r);
42 }
43 
44 PLL query(int q, int l, int r, int x)
45 {
46     if (r <= x)
47     {
48         return make_pair(t[q].s1, t[q].s2);
49     }
50 
51     int mid = (l + r) >> 1;
52     if (x <= mid) return query(q << 1, l, mid, x);
53     else return add(query(q << 1, l, mid, x), query(q << 1 | 1, mid + 1, r, x));
54 }
55 
56 int main()
57 {
58     scanf("%d%d", &n, &m);
59     for (int i = 1; i <= n; i++)
60     {
61         int x;
62         scanf("%d", &x);
63         modify(1, 1, n, i, x);
64     }
65 
66     while (m--)
67     {
68         char qu[10];
69         scanf("%s", qu);
70         if (qu[0] == 'Q')
71         {
72             int r;
73             scanf("%d", &r);
74             PLL res = query(1, 1, n, r);
75             printf("%lld\n", res.first * (r + 1) - res.second);
76         }
77         else
78         {
79             int i, x;
80             scanf("%d%d", &i, &x);
81             modify(1, 1, n, i, x);
82         }
83     }
84 }
View Code

 【ZJOI2013】k大数查询(题目):

  树状数组套线段树,树状数组的节点表示编号在【l,r】之间的集合,线段树的节点表示值在【l,r】范围的点有多少  

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 typedef long long LL;
 9 
10 const int N = 5000010;
11 
12 LL n, m;
13 LL tot, a[N];
14 LL son[N][2], lazy[N], sum[N];
15 
16 LL lowbit(LL x)
17 {
18     return x & -x; 
19 }
20 
21 LL LB(LL x)
22 {
23     return 1ll << (LL)(log2(x));
24 }
25 
26 LL q(LL& x)
27 { 
28     if (x == 0)  x = ++tot;
29     return x;
30 }
31 
32 void update(LL L, LL R, LL l, LL r, LL nod)
33 {
34     int mid = ((L + R) >> 1);
35     sum[nod] += r - l + 1;
36 
37     if (L == l && R == r) lazy[nod]++;
38     else if (r <= mid) update(L, mid, l, r, q(son[nod][0]));
39     else if (l > mid) update(mid + 1, R, l, r, q(son[nod][1]));
40     else update(L, mid, l, mid, q(son[nod][0])), update(mid + 1, R, mid + 1, r, q(son[nod][1]));
41 }
42 
43 LL query(LL L, LL R, LL l, LL r, LL nod)
44 {
45     LL mid = ((L + R) >> 1);
46     if (L == l && R == r) return sum[nod];
47     else if (r <= mid) return lazy[nod] * (r - l + 1) + (son[nod][0] == 0 ? 0 : query(L, mid, l, r, son[nod][0]));
48     else if (l > mid) return lazy[nod] * (r - l + 1) + (son[nod][1] == 0 ? 0 : query(mid + 1, R, l, r, son[nod][1]));
49     else return lazy[nod] * (r - l + 1) + (son[nod][0] == 0 ? 0 : query(L, mid, l, mid, son[nod][0])) + (son[nod][1] == 0 ? 0 : query(mid + 1, R, mid + 1, r, son[nod][1]));
50 }
51 
52 signed main() 
53 {
54     scanf("%lld%lld", &n, &m);
55     tot = n;
56     while (m--) 
57     {
58         LL opt, l, r, c;
59         scanf("%lld%lld%lld%lld", &opt, &l, &r, &c);
60         if (2 - opt)
61         {
62             for (int i = n - c + 1; i <= n; i += lowbit(i))
63             {
64                 update(1, n, l, r, i);
65             }
66         }
67         else 
68         {
69             LL num = 0, ans = 0;
70             for (int i = LB(n); i != 0; i >>= 1)
71             {
72                 if (ans + i > n) continue;
73                 LL F = query(1, n, l, r, ans + i) + num;
74                 if (F < c) ans += i, num = F;
75             }
76             ans++;
77             printf("%lld\n", n - ans + 1);
78         }
79     }
80 }
View Code

 

  ~END~

posted on 2020-06-29 22:18  ArrogHie  阅读(313)  评论(0编辑  收藏  举报