做题&学习记录(2月)
2020.2.3
学了一点多项式理论,感觉似懂非懂。。
首先注意到这是一颗完全二叉树,因为高度很小所以可以枚举每个点作为起点。
然后考虑树形DP,求出每个点往上爬的代价即可。
1 #include <bits/stdc++.h>
2 using namespace std;
3
4 typedef long long ll;
5 const int MAXN = 200010;
6 #define p(i, j) (((1 << (j - 1)) <= i) ? (i >> j) : -1)
7 #define b(i, j) ((i >> (j - 1)) ^ 1)
8 #define ls (i << 1)
9 #define rs (i << 1 | 1)
10
11 int n; ll num[MAXN];
12 ll dis[MAXN][20], dp[MAXN][20][2];
13
14 int main()
15 {
16 scanf("%d", &n);
17 for(int i = 1; i <= n; ++i) scanf("%lld", &num[i]);
18 for(int i = 2; i <= n; ++i)
19 {
20 scanf("%lld", &dis[i][1]);
21 for(int j = 2; ~p(i, j); ++j) dis[i][j] = dis[i][1] + dis[p(i, 1)][j - 1];
22 }
23 for(int i = n; i; --i)
24 for(int j = 1; ~p(i, j); ++j)
25 {
26 dp[i][j][0] = dp[i][j][1] = 0x3f3f3f3f3f3f3f3f;
27 int lson = ls, rson = rs;
28 if((i << 1) > n)
29 {
30 dp[i][j][0] = dis[i][j] * num[p(i, j)];
31 dp[i][j][1] = (dis[i][j] + dis[b(i, j)][1]) * num[b(i, j)];
32 }
33 else if((i << 1 | 1) > n)
34 {
35 dp[i][j][0] = dis[ls][1] * num[ls] + dp[ls][j + 1][0];
36 dp[i][j][1] = dis[ls][1] * num[ls] + dp[ls][j + 1][1];
37 }
38 else
39 {
40 dp[i][j][0] = min(dp[i][j][0], dis[ls][1] * num[ls] + dp[ls][1][1] + dp[rs][j + 1][0]);
41 dp[i][j][0] = min(dp[i][j][0], dis[rs][1] * num[rs] + dp[rs][1][1] + dp[ls][j + 1][0]);
42 dp[i][j][1] = min(dp[i][j][1], dis[ls][1] * num[ls] + dp[ls][1][1] + dp[rs][j + 1][1]);
43 dp[i][j][1] = min(dp[i][j][1], dis[rs][1] * num[rs] + dp[rs][1][1] + dp[ls][j + 1][1]);
44 }
45 }
46 ll ans = 0x3f3f3f3f3f3f3f3f;
47 for(int s = 1; s <= n; ++s)
48 {
49 ll tmp = dp[s][1][0];
50 for(int i = p(s, 1), lst = s; ~i; i = p(i, 1), lst = p(lst, 1))
51 {
52 if(b(lst, 1) <= n) tmp += dis[b(lst, 1)][1] * num[b(lst, 1)] + dp[b(lst, 1)][2][0];
53 else tmp += dis[i][1] * num[p(i, 1)];
54 }
55 ans = min(ans, tmp);
56 }
57 printf("%lld\n", ans);
58 return 0;
59 }
2020.2.4
二分,然后最大流判定即可。
做了一下隔壁省的省选题,,这也太水了。。
线段树维护一个最大连续子段,修改的话可以在线段树上一层层递归下去,直到当前区间能全部一次改成1再修改,时间复杂度是$O(nlog^2n)$的。
数据结构题有点难写,放个代码吧。
1 #include<bits/stdc++.h>
2 using namespace std;
3
4 const int MAXN = 200010;
5 #define ls (o << 1)
6 #define rs (o << 1 | 1)
7
8 struct Node
9 {
10 int l, r, lazy;
11 int sum, Sum;
12 }t[MAXN << 2];
13
14 int n, m, tot, cnt;
15
16 Node pushup(int l, int r, Node a, Node b, int tag)
17 {
18 Node o = (Node){a.l, b.r, tag, a.r + b.l, a.Sum + b.Sum};
19 int mid = (l + r) >> 1;
20 if(a.l == mid - l + 1) o.l += b.l;
21 if(b.r == r - mid) o.r += a.r;
22 o.sum = max(o.sum, max(a.sum, b.sum));
23 o.sum = max(o.sum, max(o.l, o.r));
24 return o;
25 }
26
27 void pushdown(int o, int l, int r)
28 {
29 int tag = t[o].lazy;
30 t[o].lazy = -1;
31 if(tag == -1) return;
32 int mid = (l + r) >> 1;
33 t[ls].Sum = tag * (mid - l + 1);
34 t[ls].sum = t[ls].l = t[ls].r = (tag == 0) * (mid - l + 1);
35 t[ls].lazy = tag;
36 t[rs].Sum = tag * (r - mid);
37 t[rs].sum = t[rs].l = t[rs].r = (tag == 0) * (r - mid);
38 t[rs].lazy = tag;
39 }
40
41 void change0(int o, int l, int r, int L, int R)
42 {
43 if(l == L && r == R)
44 {
45 t[o].Sum = 0;
46 t[o].sum = t[o].l = t[o].r = r - l + 1;
47 t[o].lazy = 0;
48 return;
49 }
50 pushdown(o, l, r);
51 int mid = (l + r) >> 1;
52 if(R <= mid) change0(ls, l, mid, L, R);
53 else if(L > mid) change0(rs, mid + 1, r, L, R);
54 else change0(ls, l, mid, L, mid), change0(rs, mid + 1, r, mid + 1, R);
55 t[o] = pushup(l, r, t[ls], t[rs], t[o].lazy);
56 }
57
58 void change1(int o, int l, int r)
59 {
60 if(!cnt) return;
61 if(t[o].Sum == r - l + 1) return;
62 if(!t[o].Sum && cnt >= r - l + 1)
63 {
64 t[o].Sum = r - l + 1;
65 t[o].sum = t[o].l = t[o].r = 0;
66 t[o].lazy = 1;
67 cnt -= r - l + 1, tot += r - l + 1;
68 return;
69 }
70 if(l >= r) return;
71 pushdown(o, l, r);
72 int mid = (l + r) >> 1;
73 change1(ls, l, mid); change1(rs, mid + 1, r);
74 t[o] = pushup(l, r, t[ls], t[rs], t[o].lazy);
75 }
76
77 void modify(int o, int l, int r, int L, int R, int tag)
78 {
79 if(tot >= tag) return;
80 if(l == L && r == R)
81 {
82 cnt = tag - tot;
83 change1(o, l, r);
84 return;
85 }
86 pushdown(o, l, r);
87 int mid = (l + r) >> 1;
88 if(R <= mid) modify(ls, l, mid, L, R, tag);
89 else if(L > mid) modify(rs, mid + 1, r, L, R, tag);
90 else modify(ls, l, mid, L, mid, tag), modify(rs, mid + 1, r, mid + 1, R, tag);
91 t[o] = pushup(l, r, t[ls], t[rs], t[o].lazy);
92 }
93
94 int ask1(int o, int l, int r, int L, int R)
95 {
96 if(l == L && r == R) return t[o].Sum;
97 pushdown(o, l, r);
98 int mid = (l + r) >> 1;
99 if(R <= mid) return ask1(ls, l, mid, L, R);
100 else if(L > mid) return ask1(rs, mid + 1, r, L, R);
101 else return ask1(ls, l, mid, L, mid) + ask1(rs, mid + 1, r, mid + 1, R);
102 }
103
104 Node ask2(int o, int l, int r, int L, int R)
105 {
106 if(l == L && r == R) return t[o];
107 pushdown(o, l, r);
108 int mid = (l + r) >> 1;
109 if(R <= mid) return ask2(ls, l, mid, L, R);
110 else if(L > mid) return ask2(rs, mid + 1, r, L, R);
111 Node a = ask2(ls, l, mid, L, mid), b = ask2(rs, mid + 1, r, mid + 1, R);
112 return pushup(l, r, a, b, -1);
113 }
114
115 int main()
116 {
117 scanf("%d %d", &n, &m);
118 t[1].lazy = 1, t[1].Sum = n;
119 for(int i = 1; i <= m; ++i)
120 {
121 int op, l, r, l1, r1;
122 scanf("%d %d %d", &op, &l, &r);
123 if(!op) change0(1, 1, n, l, r);
124 else if(op == 1)
125 {
126 scanf("%d %d", &l1, &r1);
127 int tag = ask1(1, 1, n, l, r);
128 change0(1, 1, n, l, r);
129 if(tag) tot = cnt = 0, modify(1, 1, n, l1, r1, tag);
130 }
131 else if(op == 2) printf("%d\n", ask2(1, 1, n, l, r).sum);
132 }
133 return 0;
134 }
2020.2.5
线段树套可持久化Trie,每个节点用Vector存一下时间,查询的时候二分即可。
顺便复习了一下可持久化结构。
1 #include <bits/stdc++.h>
2 using namespace std;
3
4 const int MAXN = 100010;
5 #define ls (o << 1)
6 #define rs (o << 1 | 1)
7
8 int n, m, rt[MAXN];
9
10 struct Trie
11 {
12 int ch[2], sum;
13 }t[MAXN * 120];
14 int cnt = 0;
15
16 void ins(int& o, int p, int d, int val)
17 {
18 o = ++cnt, t[o] = t[p];
19 ++t[o].sum;
20 if(d == -1) return;
21 bool c = (val & (1 << d));
22 ins(t[o].ch[c], t[p].ch[c], d - 1, val);
23 }
24
25 int ask(int l, int r, int d, int val)
26 {
27 if(d == -1 || (!l && !r)) return 0;
28 bool c = (val & (1 << d));
29 if(t[t[r].ch[!c]].sum - t[t[l].ch[!c]].sum > 0) return (1 << d) + ask(t[l].ch[!c], t[r].ch[!c], d - 1, val);
30 else return ask(t[l].ch[c], t[r].ch[c], d - 1, val);
31 }
32
33 struct Node
34 {
35 vector<int> times, ids;
36 int nowrt;
37 }s[MAXN << 2];
38
39 void build(int o, int l, int r)
40 {
41 s[o].times.push_back(0);
42 s[o].ids.push_back(0);
43 s[o].nowrt = 0;
44 if(l == r) return;
45 int mid = (l + r) >> 1;
46 build(ls, l, mid);
47 build(rs, mid + 1, r);
48 }
49
50 void modify(int o, int l, int r, int pos, int val, int day)
51 {
52 s[o].times.push_back(day);
53 int copy = 0;
54 ins(copy, s[o].nowrt, 17, val);
55 s[o].ids.push_back(copy);
56 s[o].nowrt = copy;
57 if(l == r) return;
58 int mid = (l + r) >> 1;
59 if(pos <= mid) modify(ls, l, mid, pos, val, day);
60 else modify(rs, mid + 1, r, pos, val, day);
61 }
62
63 int query(int o, int l, int r, int L, int R, int x, int d, int day)
64 {
65 if(L <= l && r <= R)
66 {
67 if(s[o].times.size() <= 1 || s[o].times.back() < day - d + 1) return 0;
68 int siz = (int)s[o].times.size();
69 int l = 1, r = siz - 1, ans = siz - 1;
70 while(l <= r)
71 {
72 int mid = (l + r) >> 1;
73 if(s[o].times[mid] >= day - d + 1) ans = mid, r = mid - 1;
74 else l = mid + 1;
75 }
76 return ask(s[o].ids[ans - 1], s[o].nowrt, 17, x);
77 }
78 int mid = (l + r) >> 1, res = 0;
79 if(L <= mid) res = max(res, query(ls, l, mid, L, R, x, d, day));
80 if(R > mid) res = max(res, query(rs, mid + 1, r, L, R, x, d, day));
81 return res;
82 }
83
84 int main()
85 {
86 int day = 0;
87 scanf("%d %d", &n, &m);
88 for(int i = 1; i <= n; ++i)
89 {
90 int x; scanf("%d", &x);
91 ins(rt[i], rt[i - 1], 17, x);
92 }
93 build(1, 1, n);
94 while(m--)
95 {
96 int op, l, r, x, d;
97 scanf("%d", &op);
98 if(!op) ++day;
99 if(!op)
100 {
101 scanf("%d %d", &x, &d);
102 modify(1, 1, n, x, d, day);
103 }
104 else if(op == 1)
105 {
106 scanf("%d %d %d %d", &l, &r, &x, &d);
107 int ans = ask(rt[l - 1], rt[r], 17, x);
108 ans = max(ans, query(1, 1, n, l, r, x, d, day));
109 printf("%d\n", ans);
110 }
111 }
112 return 0;
113 }
2020.2.6
二合一的题目,$c_i<=1$时贪心,否则做一个类似背包的树形DP即可。
做法很多,什么最小表示法等等,不过直接简单粗暴的树哈希就可以了。