2017雅礼省选集训做题记录

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017雅礼省选集训做题记录相关的知识,希望对你有一定的参考价值。

嘛,最近在补雅礼省选前集训的题。都是我会做的题。。那一定是最水的那些题啦

题目在loj.ac上都有。过段时间如果搬了雅礼NOI集训的题应该也会做做的吧。。

 

Day1

T1

一道经典套路题,做法跟UOJ #228基础数据结构练习题类似。

使用线段树维护。考虑相邻两个数的差值最多变化log次。也就是说,对于每个区间,只要操作二进行大概log次就能使得这个区间内所有数完全一样。所以对于操作二,只要记录一下区间最大最小值,就能直接打标记或者暴力DFS下去。

和UOJ那个题一样,注意一个特殊情况,就是一个区间有两种数,不过大的那个能够被d整除,这时候就可以直接打一个减法标记。不考虑这个情况复杂度会被卡成平方。

技术分享
  1 #include <cstdio>
  2 #include <algorithm>
  3 
  4 using namespace std;
  5 
  6 void Get_Val(int &Ret)
  7 {
  8     Ret = 0;
  9     char ch;
 10     bool Neg(false);
 11     while (ch = getchar(), (ch > 9 || ch < 0) && ch != -)
 12         ;
 13     if (ch == -)
 14     {
 15         Neg = true;
 16         while (ch = getchar(), ch > 9 || ch < 0)
 17             ;
 18     }
 19     do
 20     {
 21         (Ret *= 10) += ch - 0;
 22     }
 23     while (ch = getchar(), ch >= 0 && ch <= 9);
 24     Ret = (Neg ? -Ret : Ret);
 25 }
 26 
 27 const int Max_N(100050);
 28 const int INF(2100000000);
 29 typedef long long int LL;
 30 
 31 int N, Q, A[Max_N];
 32 
 33 #define LEFT  (segt[cur].l)
 34 #define RIGHT (segt[cur].r)
 35 #define MID   (segt[cur].mid)
 36 #define MIN   (segt[cur].Min)
 37 #define MAX   (segt[cur].Max)
 38 #define SUM   (segt[cur].Sum)
 39 #define ADD   (segt[cur].Add)
 40 #define COV   (segt[cur].Cov)
 41 #define LCH   (cur << 1)
 42 #define RCH   ((cur << 1) | 1)
 43 
 44 inline int mydiv(const int &n, const int &d)
 45 {
 46     return n >= 0 ? n / d : n / d - (n % d != 0);
 47 }
 48 
 49 struct node
 50 {
 51     int l, r, mid, Min, Max, Add, Cov;
 52     LL Sum;
 53 };
 54 
 55 struct Segment_Tree
 56 {
 57     node segt[Max_N << 2];
 58     inline void pushup(const int &cur)
 59     {
 60         MIN = min(segt[LCH].Min, segt[RCH].Min);
 61         MAX = max(segt[LCH].Max, segt[RCH].Max);
 62         SUM = segt[LCH].Sum + segt[RCH].Sum;
 63     }
 64     inline void cover(const int &cur, const int &v)
 65     {
 66         MIN = MAX = v, SUM = (v * 1LL) * (RIGHT - LEFT + 1LL), COV = v, ADD = 0;
 67     }
 68     inline void plus(const int &cur, const int &v)
 69     {
 70         MIN += v, MAX += v, SUM += (v * 1LL) * (RIGHT - LEFT + 1LL), ADD += v;
 71     }
 72     inline void pushdown(const int &cur)
 73     {
 74         if (COV != INF)
 75             cover(LCH, COV), cover(RCH, COV), COV = INF;
 76         if (ADD)
 77             plus(LCH, ADD), plus(RCH, ADD), ADD = 0;
 78     }
 79     void build_tree(const int&, const int&, const int&);
 80     LL querySum(const int&, const int&, const int&);
 81     int queryMin(const int&, const int&, const int&);
 82     void Plus(const int&, const int&, const int&, const int&);
 83     void Div(const int&, const int&, const int&, const int&);
 84 };
 85 Segment_Tree seg;
 86 
 87 void Segment_Tree::build_tree(const int &cur, const int &l, const int &r)
 88 {
 89     LEFT = l, RIGHT = r, MID = l + ((r - l) >> 1), ADD = 0, COV = INF;
 90     if (l == r)
 91     {
 92         MIN = MAX = SUM = A[l];
 93         return;
 94     }
 95     build_tree(LCH, l, MID), build_tree(RCH, MID + 1, r), pushup(cur);
 96 }
 97 
 98 LL Segment_Tree::querySum(const int &cur, const int &l, const int &r)
 99 {
100     if (LEFT == l && RIGHT == r)
101         return SUM;
102     pushdown(cur);
103     if (r <= MID)
104         return querySum(LCH, l, r);
105     else
106         if (l > MID)
107             return querySum(RCH, l, r);
108         else
109             return querySum(LCH, l, MID) + querySum(RCH, MID + 1, r);
110 }
111 
112 int Segment_Tree::queryMin(const int &cur, const int &l, const int &r)
113 {
114     if (LEFT == l && RIGHT == r)
115         return MIN;
116     pushdown(cur);
117     if (r <= MID)
118         return queryMin(LCH, l, r);
119     else
120         if (l > MID)
121             return queryMin(RCH, l, r);
122         else
123             return min(queryMin(LCH, l, MID), queryMin(RCH, MID + 1, r));
124 }
125 
126 void Segment_Tree::Plus(const int &cur, const int &l, const int &r, const int &v)
127 {
128     if (LEFT == l && RIGHT == r)
129     {
130         plus(cur, v);
131         return;
132     }
133     pushdown(cur);
134     if (r <= MID)
135         Plus(LCH, l, r, v);
136     else
137         if (l > MID)
138             Plus(RCH, l, r, v);
139         else
140             Plus(LCH, l, MID, v), Plus(RCH, MID + 1, r, v);
141     pushup(cur);
142 }
143 
144 void Segment_Tree::Div(const int &cur, const int &l, const int &r, const int &d)
145 {
146     if (LEFT == l && RIGHT == r)
147     {
148         if (mydiv(MIN, d) == mydiv(MAX, d))
149             cover(cur, mydiv(MIN, d));
150         else
151             if (MAX - MIN <= 1 && MAX - mydiv(MAX, d) == MIN - mydiv(MIN, d))
152                 plus(cur, mydiv(MAX, d) - MAX);
153             else
154                 pushdown(cur), Div(LCH, l, MID, d), Div(RCH, MID + 1, r, d), pushup(cur);
155         return;
156     }
157     pushdown(cur);
158     if (r <= MID)
159         Div(LCH, l, r, d);
160     else
161         if (l > MID)
162             Div(RCH, l, r, d);
163         else
164             Div(LCH, l, MID, d), Div(RCH, MID + 1, r, d);
165     pushup(cur);
166 }
167 
168 void init()
169 {
170     Get_Val(N), Get_Val(Q);
171     for (int i = 1;i <= N;++i)
172         Get_Val(A[i]);
173     seg.build_tree(1, 1, N);
174 }
175 
176 void work()
177 {
178     int op, l, r, v;
179     while (Q--)
180     {
181         Get_Val(op), Get_Val(l), Get_Val(r), ++l, ++r;
182         if (op == 1)
183             Get_Val(v), seg.Plus(1, l, r, v);
184         if (op == 2)
185             Get_Val(v), seg.Div(1, l, r, v);
186         if (op == 3)
187             printf("%d\n", seg.queryMin(1, l, r));
188         if (op == 4)
189             printf("%lld\n", seg.querySum(1, l, r));
190     }
191 }
192 
193 int main()
194 {
195     init();
196     work();
197     return 0;
198 }
Day1T1

 

T2

考虑贪心。最优策略一定是,先把第i行任意一个黑色格子那一列提出来,设这个格子为(i,j),然后去把第j行全部染成黑色,最后用第j行去染其它所有行。注意考虑一些奇怪的情况。

不过我的代码好像有锅。。但反正A掉了就没管了。。

技术分享
 1 #include <cstdio>
 2 #include <algorithm>
 3 
 4 using namespace std;
 5 
 6 const int Max_N(1050);
 7 
 8 int N;
 9 char S[Max_N][Max_N];
10 int Black[Max_N];
11 bool AllWhite;
12 
13 void init()
14 {
15     AllWhite = true;
16     scanf("%d", &N);
17     for (int i = 1;i <= N;++i)
18     {
19         scanf("%s", S[i] + 1);
20         for (int j = 1;j <= N;++j)
21             AllWhite = (S[i][j] == # ? false: AllWhite), Black[j] += (S[i][j] == #);
22     }
23 }
24 
25 void work()
26 {
27     int Ans(N << 1);
28     for (int i = 1, Ret = 0;i <= N;++i)
29     {
30         Ret = 1;
31         for (int j = 1;j <= N;++j)
32             if (S[j][i] == #)
33             {
34                 Ret = 0;
35                 break;
36             }
37         for (int j = 1;j <= N;++j)
38             if (S[i][j] == .)
39                 ++Ret;
40         for (int k = 1;k <= N;++k)
41             if (Black[k] < N)
42                 ++Ret;
43         Ans = min(Ans, Ret);
44     }
45     printf("%d", Ans);
46 }
47 
48 int main()
49 {
50     init();
51     if (AllWhite)
52         printf("-1");
53     else
54         work();
55     return 0;
56 }
Day1T2

 

T3

我们首先考虑两种暴力。

第一种暴力是,对于每个询问,直接枚举在a到b之间的i对应的li和ri,然后累加答案。

第二种暴力是,对于每个询问,枚举这个字符串w的O(k^2)个子串,然后计算每个子串在a到b之间有多少个,累加他们对于答案的贡献。

因为我比较菜不会SAM,所以所有计算w的某个子串在某一段字符串中出现次数我是用SA实现的。

注意到Q*K<=2*10^5,这提示我们可以考虑根号分治。我们设定一个阈值为r=sqrt(2*10^5),如果字符串长度大于r,那么询问个数一定小于r。那么复杂度就是O(qsqrt(2*10^5)*logn);如果字符串长度小于r,那么所有的字符串子串之和就是Σr^2<=Σr*sqrt(2*10^5),那么我们的复杂度就是O(Q*Ksqrt(2*10^5)*logn)。

这两个复杂度都是可以接受的。只是实现起来用SA可能要卡常,对于第一种暴力我是用一种奇怪的并查集做法来实现的。

(出题人给的标算用的是SAM)

技术分享
  1 #include <cmath>
  2 #include <vector>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <algorithm>
  6 
  7 using namespace std;
  8 
  9 void Get_Val(int &Ret)
 10 {
 11     Ret = 0;
 12     char ch;
 13     while (ch = getchar(), ch > 9 || ch < 0)
 14         ;
 15     do
 16     {
 17         (Ret *= 10) += ch - 0;
 18     }
 19     while (ch = getchar(), ch >= 0 && ch <= 9);
 20 }
 21 
 22 const int Max_N(300050);
 23 const int Max_M(100050);
 24 const int Max_Q(100050);
 25 const int Max_K(100050);
 26 typedef long long int LL;
 27 
 28 int _N, N, M, Mcut, Q, K, L[Max_M], R[Max_M], St[Max_Q], A[Max_Q], B[Max_Q], S[Max_N], InS[Max_N];
 29 char _S[Max_N];
 30 
 31 void init()
 32 {
 33     Get_Val(_N), Get_Val(M), Get_Val(Q), Get_Val(K);
 34     scanf("%s", _S + 1);
 35     for (int i = 1;i <= M;++i)
 36         Get_Val(L[i]), Get_Val(R[i]), ++L[i], ++R[i];
 37     for (int i = 1;i <= _N;++i)
 38         S[i] = _S[i];
 39     N = _N;
 40     for (int i = 1;i <= Q;++i)
 41     {
 42         scanf("%s", _S + 1), Get_Val(A[i]), Get_Val(B[i]), ++A[i], ++B[i];
 43         S[++N] = 100000 + i, St[i] = N;
 44         for (int j = 1;j <= K;++j)
 45             S[++N] = _S[j];
 46     }
 47     
 48 }
 49 
 50 int SA[Max_N], wa[Max_N], wb[Max_N], Cnt[Max_N];
 51 int Rank[Max_N], Height[Max_N], ST[20][Max_N], Log[Max_N];
 52 void getSA()
 53 {
 54     int M = 200050, *x = wa, *y = wb;
 55     memset(Cnt, 0, sizeof(Cnt));
 56     for (int i = 1;i <= N;++i)
 57         ++Cnt[x[i] = S[i]];
 58     for (int i = 1;i <= M;++i)
 59         Cnt[i] += Cnt[i - 1];
 60     for (int i = N;i >= 1;--i)
 61         SA[Cnt[x[i]]--] = i;
 62     for (int k = 1, p;k <= N;k <<= 1)
 63     {
 64         p = 0;
 65         for (int i = N - k + 1;i <= N;++i)
 66             y[++p] = i;
 67         for (int i = 1;i <= N;++i)
 68             if (SA[i] > k)
 69                 y[++p] = SA[i] - k;
 70         memset(Cnt, 0, sizeof(Cnt));
 71         for (int i = 1;i <= N;++i)
 72             ++Cnt[x[i]];
 73         for (int i = 1;i <= M;++i)
 74             Cnt[i] += Cnt[i - 1];
 75         for (int i = N;i >= 1;--i)
 76             SA[Cnt[x[y[i]]]--] = y[i];
 77         swap(x, y), x[SA[1]] = (p = 1);
 78         for (int i = 2;i <= N;++i)
 79         {
 80             if (y[SA[i - 1]] != y[SA[i]] || y[SA[i - 1] + k] != y[SA[i] + k])
 81                 ++p;
 82             x[SA[i]] = p;
 83         }
 84         if ((M = p) == N)
 85             break;
 86     }
 87     for (int i = 1;i <= N;++i)
 88     {
 89         Rank[SA[i]] = i;
 90         InS[i] = InS[i - 1] + (SA[i] <= _N);
 91     }
 92     for (int i = 1, k = 0, j;i <= N;++i)
 93     {
 94         if (k)
 95             --k;
 96         j = SA[Rank[i] - 1];
 97         while (S[i + k] == S[j + k])
 98             ++k;
 99         Height[Rank[i]] = k;
100     }
101 }
102 
103 inline int rmq(const int &l, const int &r)
104 {
105     static int rmqk;
106     rmqk = Log[r - l + 1];
107     return min(ST[rmqk][l], ST[rmqk][r - (1 << rmqk) + 1]);
108 }
109 
110 int query(const int &pos, const int &len)
111 {
112     int l, r, mid, up, down;
113     if (pos == 1)
114         up = 1;
115     else
116     {
117         l = 1, r = pos;
118         while (l < r)
119         {
120             mid = l + ((r - l) >> 1);
121             if (rmq(mid + 1, pos) >= len)
122                 r = mid;
123             else
124                 l = mid + 1;
125         }
126         up = l;
127     }
128     if (pos == N)
129         down = N;
130     else
131     {
132         l = pos + 1, r = N + 1;
133         while  (l < r)
134         {
135             mid = l + ((r - l) >> 1);
136             if (rmq(pos + 1, mid) >= len)
137                 l = mid + 1;
138             else
139                 r = mid;
140         }
141         down = l - 1;
142     }
143     return InS[down] - InS[up - 1];
144 }
145 
146 struct edge
147 {
148     int u, v, w;
149     void give(const int &_u, const int &_v, const int &_w)
150     {
151         u = _u, v = _v, w = _w;
152     }
153 };
154 edge Edges[Max_N];
155 int Father[Max_N], lb[Max_N], rb[Max_N];
156 LL Ans[Max_Q];
157 
158 inline bool operator<(const edge &a, const edge &b)
159 {
160     return a.w > b.w;
161 }
162 
163 int Get_Father(const int &x)
164 {
165     return Father[x] == x ? x : Father[x] = Get_Father(Father[x]);
166 }
167 
168 struct ask
169 {
170     int pos, len;
171     void give(const int &_pos, const int &_len)
172     {
173         pos = _pos, len = _len;
174     }
175 };
176 ask Ask[Max_M];
177 
178 inline bool operator<(const ask &a, const ask &b)
179 {
180     return a.len > b.len;
181 }
182 
183 void work1()
184 {
185     for (int i = 1;i <= N;++i)
186         Father[i] = i, lb[i] = rb[i] = i;
187     for (int i = 2;i <= N;++i)
188         Edges[i - 1].give(i - 1, i, Height[i]);
189     for (int i = 1;i <= M;++i)
190         Ask[i].give(i, R[i] - L[i] + 1);
191     sort(Edges + 1, Edges + 1 + (N - 1));
192     sort(Ask + 1, Ask + 1 + M);
193     for (register int i = 1, j = 1, u, v, askp;i <= M;++i)
194     {
195         while (j <= N - 1 && Edges[j].w >= Ask[i].len)
196         {
197             if ((u = Get_Father(Edges[j].u)) != (v = Get_Father(Edges[j].v)))
198                 Father[v] = u, lb[u] = min(lb[u], lb[v]), rb[u] = max(rb[u], rb[v]);
199             ++j;
200         }
201         askp = Ask[i].pos;
202         for (int q = 1, pos;q <= Q;++q)
203             if (A[q] <= askp && askp <= B[q])
204             {
205                 pos = Get_Father(Rank[St[q] + L[askp]]);
206                 Ans[q] += InS[rb[pos]] - InS[lb[pos] - 1];
207             }
208     }
209     for (int i = 1;i <= Q;++i)
210         printf("%lld\n", Ans[i]);
211 }
212 
213 vector<int> PP[Max_M];
214 
215 int query(const vector<int> &Pos, const int &up, const int &down)
216 {
217     if (!Pos.size())
218         return 0;
219     if (Pos[Pos.size() - 1] < up)
220         return 0;
221     if (Pos[0] > down)
222         return 0;
223     int ll, rr, l, r, mid;
224     l = 0, r = Pos.size() - 1;
225     while (l < r)
226     {
227         mid = l + ((r - l) >> 1);
228         if (Pos[mid] >= up)
229             r = mid;
230         else
231             l = mid + 1;
232     }
233     ll = l;
234     l = 0, r = Pos.size();
235     while (l < r)
236     {
237         mid = l + ((r - l) >> 1);
238         if (Pos[mid] <= down)
239             l = mid + 1;
240         else
241             r = mid;
242     }
243     rr = l - 1;
244     return ll <= rr ? rr - ll + 1 : 0;
245 }
246 
247 void work2()
248 {
249     for (int i = 1;i <= N;++i)
250         ST[0][i] = Height[i];
251     for (int j = 1;(1 << j) <= N;++j)
252         for (int i = 1;i + (1 << j) - 1 <= N;++i)
253             ST[j][i] = min(ST[j - 1][i], ST[j - 1][i + (1 << (j - 1))]);
254     Log[0] = Log[1] = 0;
255     for (int i = 2;i <= N;++i)
256         Log[i] = Log[i >> 1] + 1;
257     LL Ans, qwq;
258     for (int i = 1;i <= M;++i)
259         PP[(L[i] - 1) * K + R[i]].push_back(i);
260     for (int i = 1;i <= Q;++i)
261     {
262         Ans = 0LL;
263         for (int a = 1;a <= K;++a)
264             for (int b = a;b <= K;++b)
265                 if (qwq = query(PP[(a - 1) * K + b], A[i], B[i]))
266                     Ans += (query(Rank[St[i] + a], b - a + 1) * 1LL) * (qwq * 1LL);
267         printf("%lld\n", Ans);
268     }
269 }
270 
271 int main()
272 {
273     init();
274     getSA();
275     Mcut = static_cast<int>(sqrt(M * 1.0));
276     if (K >= Mcut)
277         work1();
278     else
279         work2();
280     return 0;
281 }
Day1T3

 

 

Day2

T1

这个题我一开始不大会,看了solution也没有看懂出题人给的做法。后来去膜了一发kry的做法。

设F[i][j]表示dp到第i个格子,第i个格子的水位高度为j可以满足的最多条件。设第i个格子左边的挡板高度为H[i],那么当j<=H[i]的时候,它可以由所有0<=k<=H[i]的F[i][k]转移过来,具体而言就是max{F[i][k],0<=k<=H[i]};当j>H[i]的时候,它可以由F[i-1][j]转移过来。我们用线段树维护第二维,前一种情况是区间覆盖,后一种情况是区间加法。然后分O(m)段考虑所有为1的条件,至于为0的条件可以最后加上去。

技术分享
  1 #include <map>
  2 #include <cstdio>
  3 #include <vector>
  4 #include <algorithm>
  5 
  6 using namespace std;
  7 
  8 void Get_Val(int &Ret)
  9 {
 10     Ret = 0;
 11     char ch;
 12     while (ch = getchar(), ch > 9 || ch < 0)
 13         ;
 14     do
 15     {
 16         (Ret *= 10) += ch - 0;
 17     }
 18     while (ch = getchar(), ch >= 0 && ch <= 9);
 19 }
 20 
 21 const int Max_N(100050);
 22 const int Max_M(300050);
 23 
 24 int N, M, H[Max_N];
 25 vector<int> V0[Max_N], V1[Max_N];
 26 int Tot, P[Max_M];
 27 
 28 void clear()
 29 {
 30     Tot = 0;
 31     for (int i = 1;i <= N;++i)
 32         V0[i].clear(), V1[i].clear();
 33 }
 34 
 35 void init()
 36 {
 37     Get_Val(N), Get_Val(M);
 38     for (int i = 2;i <= N;++i)
 39         Get_Val(H[i]);
 40     int x, y, k;
 41     while (M--)
 42     {
 43         Get_Val(x), Get_Val(y), Get_Val(k);
 44         if (k)
 45             V1[x].push_back(y);
 46         else
 47             V0[x].push_back(y);
 48     }
 49 }
 50 
 51 void lisanhua()
 52 {
 53     H[1] = 0;
 54     for (int i = 1;i <= N;++i)
 55     {
 56         P[++Tot] = H[i];
 57         for (int j = 0;j != V0[i].size();++j)
 58             P[++Tot] = V0[i][j], P[++Tot] = V0[i][j] + 1;
 59         for (int j = 0;j != V1[i].size();++j)
 60             P[++Tot] = V1[i][j], P[++Tot] = V1[i][j] + 1;
 61     }
 62     sort(P + 1, P + 1 + Tot);
 63     map<int, int> S;
 64     S[P[1]] = (M = 0);
 65     for (int i = 2;i <= Tot;++i)
 66     {
 67         if (P[i] != P[i - 1])
 68             ++M;
 69         S[P[i]] = M;
 70     }
 71     H[1] = ++M;
 72     for (int i = 2;i <= N;++i)
 73         H[i] = S[H[i]];
 74     for (int i = 1;i <= N;++i)
 75     {
 76         sort(V1[i].begin(), V1[i].end());
 77         for (int j = 0;j != V0[i].size();++j)
 78             V0[i][j] = S[V0[i][j]];
 79         for (int j = 0;j != V1[i].size();++j)
 80             V1[i][j] = S[V1[i][j]];
 81     }
 82 }
 83 
 84 #define LEFT  (segt[cur].l)
 85 #define RIGHT (segt[cur].r)
 86 #define MID   (segt[cur].mid)
 87 #define MAX   (segt[cur].Max)
 88 #define TAG1  (segt[cur].Tag1)
 89 #define TAG2  (segt[cur].Tag2)
 90 #define LCH   (cur << 1)
 91 #define RCH   ((cur << 1) | 1)
 92 
 93 struct node
 94 {
 95     int l, r, mid;
 96     int Max, Tag1, Tag2;
 97 };
 98 
 99 struct Segment_Tree
100 {
101     node segt[Max_M << 2];
102     inline void pushup(const int &cur)
103     {
104         MAX = max(segt[LCH].Max, segt[RCH].Max);
105     }
106     inline void Cov(const int &cur, const int &v)
107     {
108         MAX = v, TAG1 = v, TAG2 = 0;
109     }
110     inline void Add(const int &cur, const int &v)
111     {
112         MAX += v, TAG2 += v;
113     }
114     inline void pushdown(const int &cur)
115     {
116         if (TAG1 != -1)
117             Cov(LCH, TAG1), Cov(RCH, TAG1), TAG1 = -1;
118         if (TAG2)
119             Add(LCH, TAG2), Add(RCH, TAG2), TAG2 = 0;
120     }
121     void build_tree(const int&, const int&, const int&);
122     void Cover(const int&, const int&, const int&, const int&);
123     void Plus(const int&, const int&, const int&, const int&);
124     int query(const int&, const int&, const int&);
125 };
126 Segment_Tree seg;
127 
128 void Segment_Tree::build_tree(const int &cur, const int &l, const int &r)
129 {
130     LEFT = l, RIGHT = r, MID = l + ((r - l) >> 1), MAX = 0, TAG1 = -1, TAG2 = 0;
131     if (l == r)
132         return;
133     build_tree(LCH, l, MID), build_tree(RCH, MID + 1, r);
134 }
135 
136 void Segment_Tree::Cover(const int &cur, const int &l, const int &r, const int &v)
137 {
138     if (LEFT == l && RIGHT == r)
139     {
140         Cov(cur, v);
141         return;
142     }
143     pushdown(cur);
144     if (r <= MID)
145         Cover(LCH, l, r, v);
146     else
147         if (l > MID)
148             Cover(RCH, l, r, v);
149         else
150             Cover(LCH, l, MID, v), Cover(RCH, MID + 1, r, v);
151     pushup(cur);
152 }
153 
154 void Segment_Tree::Plus(const int &cur, const int &l, const int &r, const int &v)
155 {
156     if (LEFT == l && RIGHT == r)
157     {
158         Add(cur, v);
159         return;
160     }
161     pushdown(cur);
162     if (r <= MID)
163         Plus(LCH, l, r, v);
164     else
165         if (l > MID)
166             Plus(RCH, l, r, v);
167         else
168             Plus(LCH, l, MID, v), Plus(RCH, MID + 1, r, v);
169     pushup(cur);
170 }
171 
172 int Segment_Tree::query(const int &cur, const int &l, const int &r)
173 {
174     if (LEFT == l && RIGHT == r)
175         return MAX;
176     pushdown(cur);
177     if (r <= MID)
178         return query(LCH, l, r);
179     else
180         if (l > MID)
181             return query(RCH, l, r);
182         else
183             return max(query(LCH, l, MID), query(RCH, MID + 1, r));
184 }
185 
186 void dp()
187 {
188     seg.build_tree(1, 0, M);
189     for (int i = 1, QAQ;i <= N;++i)
190     {
191         QAQ = seg.query(1, 0, H[i]);
192         seg.Cover(1, 0, H[i], QAQ);
193         if (V1[i].size())
194         {
195             if (V1[i][V1[i].size() - 1] < H[i])
196             {
197                 for (int j = V1[i].size() - 1;j >= 0;--j)
198                     if (j == V1[i].size() - 1)
199                         seg.Cover(1, V1[i][j] + 1, H[i], QAQ + (j + 1));
200                     else
201                         if (V1[i][j + 1] != V1[i][j])
202                             seg.Cover(1, V1[i][j] + 1, V1[i][j + 1], QAQ + (j + 1));
203                 if (H[i] + 1 <= M)
204                     seg.Plus(1, H[i] + 1, M, V1[i].size());
205             }
206             else
207                 for (int t = 0;t != V1[i].size();++t)
208                     if (V1[i][t] >= H[i])
209                     {
210                         for (int j = t - 1;j >= 0;--j)
211                             if (j == t - 1)
212                                 seg.Cover(1, V1[i][j] + 1, H[i], QAQ + (j + 1));
213                             else
214                                 if (V1[i][j + 1] != V1[i][j])
215                                     seg.Cover(1, V1[i][j] + 1, V1[i][j + 1], QAQ + (j + 1));
216                         if (H[i] + 1 <= M)
217                             seg.Plus(1, H[i] + 1, M, t);
218                         for (int j = t;j != V1[i].size();++j)
219                             seg.Plus(1, V1[i][j] + 1, M, +1);
220                         break;
221                     }
222         }
223         for (int j = 0;j != V0[i].size();++j)
224             seg.Plus(1, 0, V0[i][j], +1);
225     }
226     printf("%d\n", seg.segt[1].Max);
227 }
228 
229 int main()
230 {
231     int T;
232     Get_Val(T);
233     while (T--)
234     {
235         clear();
236         init();
237         lisanhua();
238         dp();
239     }
240     return 0;
241 }
Day2T1

 

T2

一个经典问题,具体做法见NOI2011 兔兔与蛋蛋。需要注意的trick一个是这个博弈问题的经典结论,还有就是如何判断一个点或者一条边是否一定在二分图最大匹配上:从未匹配点开始用DFS或者BFS找交错轨不断标记即可。

技术分享
  1 #include <queue>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 
  6 using namespace std;
  7 
  8 void Get_Val(int &Ret)
  9 {
 10     Ret = 0;
 11     char ch;
 12     while (ch = getchar(), ch > 9 || ch < 0)
 13         ;
 14     do
 15     {
 16         (Ret *= 10) += ch - 0;
 17     }
 18     while (ch = getchar(), ch >= 0 && ch <= 9);
 19 }
 20 
 21 const int Max_NM(105);
 22 const int Max_V(105 * 105);
 23 const int Max_E((105 * 105 + 105 * 105 * 4) * 2);
 24 const int INF(0X3F3F3F3F);
 25 
 26 bool left[Max_V], can[Max_V], done[2][Max_V];
 27 
 28 struct Graph
 29 {
 30     void start(const int &v, const int &s, const int &t)
 31     {
 32         V = v, S = s, T = t, Total = 0;
 33         memset(Head, 0, sizeof(Head));
 34         memset(To, 0, sizeof(To)), memset(Next, 0, sizeof(Next));
 35         memset(Cap, 0, sizeof(Cap)), memset(Flow, 0, sizeof(Flow));
 36     }
 37     int V, S, T;
 38     int Head[Max_V], Total, To[Max_E], Next[Max_E], Cap[Max_E], Flow[Max_E];
 39     int Dist[Max_V], Cur[Max_V];
 40     inline void Add_Edge(const int &tot, const int &s, const int &t, const int &c)
 41     {
 42         To[tot] = t, Next[tot] = Head[s], Head[s] = tot, Cap[tot] = c, Flow[tot] = 0;
 43     }
 44     inline void Add_Link(const int &s, const int &t, const int &c)
 45     {
 46         Total += 2, Add_Edge(Total, s, t, c), Add_Edge(Total ^ 1, t, s, 0);
 47     }
 48     bool BFS()
 49     {
 50         queue<int> Q;
 51         memset(Dist, 0, sizeof(Dist)), Q.push(S), Dist[S] = 1;
 52         int u, v;
 53         while (Q.size())
 54         {
 55             u = Q.front(), Q.pop();
 56             for (int i = Head[u];i;i = Next[i])
 57                 if (Cap[i] > Flow[i] && !Dist[v = To[i]])
 58                     Dist[v] = Dist[u] + 1, Q.push(v);
 59         }
 60         return Dist[T];
 61     }
 62     int DFS(const int&, int);
 63     int Dinic()
 64     {
 65         int Ans(0);
 66         while (BFS())
 67         {
 68             for (int i = 1;i <= V;++i)
 69                 Cur[i] = Head[i];
 70             Ans += DFS(S, INF);
 71         }
 72         return Ans;
 73     }
 74     void bianli(const int&, const int&);
 75 };
 76 Graph G;
 77 
 78 void Graph::bianli(const int &u, const int &c)
 79 {
 80     done[c][u] = true;
 81     if (left[u] == c)
 82         can[u] = true;
 83     for (int i = Head[u], v;i;i = Next[i])
 84         if (!done[c][v = To[i]] && ((Cap[i] == Flow[i]) ^ c))
 85             bianli(v, c);
 86 }
 87 
 88 int Graph::DFS(const int &u, int a)
 89 {
 90     if (u == T || a == 0)
 91         return a;
 92     int f, Ans(0), v;
 93     for (int &i = Cur[u];i;i = Next[i])
 94         if (Dist[v = To[i]] == Dist[u] + 1 && (f = DFS(v, min(a, Cap[i] - Flow[i]))) > 0)
 95         {
 96             Ans += f, Flow[i] += f, Flow[i ^ 1] -= f;
 97             if ((a -= f) == 0)
 98                 break;
 99         }
100     return Ans;
101 }
102 
103 int N, M;
104 char S[Max_NM][Max_NM];
105 
106 inline bool test(const int &x, const int &y)
107 {
108     return x >= 1 && x <= N && y >= 1 && y <= M;
109 }
110 
111 inline int getnumber(const int &x, const int &y)
112 {
113     return (x - 1) * M + y;
114 }
115 
116 void init()
117 {
118     scanf("%d%d", &N, &M);
119     for (int i = 1;i <= N;++i)
120         scanf("%s", S[i] + 1);
121 }
122 
123 void makegraph()
124 {
125     const int dx[] = {+1, -1, +0, +0};
126     const int dy[] = {+0, +0, +1, -1};
127     G.start(N * M + 2, N * M + 1, N * M + 2);
128     for (int i = 1;i <= N;++i)
129         for (int j = 1;j <= M;++j)
130             if (S[i][j] == .)
131                 if ((i + j) & 1)
132                 {
133                     G.Add_Link(G.S, getnumber(i, j), 1);
134                     left[getnumber(i, j)] = true;
135                     for (int k = 0, x, y;k != 4;++k)
136                         if (test(x = i + dx[k], y = j + dy[k]) && S[x][y] == .)
137                             G.Add_Link(getnumber(i, j), getnumber(x, y), 1);
138                 }
139                 else
140                     G.Add_Link(getnumber(i, j), G.T, 1);
141 }
142 
143 void work()
144 {
145     G.Dinic();
146     G.bianli(G.S, 1), G.bianli(G.T, 0);
147     int cnt(0);
148     for (int i = 1;i <= N * M;++i)
149         cnt += can[i];
150     printf("%d\n", cnt);
151     for (int i = 1;i <= N;++i)
152         for (int j = 1;j <= M;++j)
153             if (can[getnumber(i, j)])
154                 printf("%d %d\n", i, j);
155 }
156 
157 int main()
158 {
159     init();
160     makegraph();
161     work();
162     return 0;
163 }
Day2T2

 

T3

李超线段树裸题。一个区间有两条线段就把“优势区间”较小的那一条线段往对应的一侧不断下传即可。

技术分享
  1 #include <cstdio>
  2 #include <algorithm>
  3 
  4 using namespace std;
  5 
  6 const int Max_X(100050);
  7 
  8 void Get_Val(int &Ret)
  9 {
 10     Ret = 0;
 11     char ch;
 12     bool Neg(false);
 13     while (ch = getchar(), (ch > 9 || ch < 0) && ch != -)
 14         ;
 15     if (ch == -)
 16     {
 17         Neg = true;
 18         while (ch = getchar(), ch > 9 || ch < 0)
 19             ;
 20     }
 21     do
 22     {
 23         (Ret *= 10) += ch - 0;
 24     }
 25     while (ch = getchar(), ch >= 0 && ch <= 9);
 26     Ret = (Neg ? -Ret : Ret);
 27 }
 28 
 29 struct segment
 30 {
 31     segment(const int &_x1 = 0, const int &_y1 = 0, const int &_x2 = 0, const int &_y2 = 0) : 
 32     x1(_x1), y1(_y1), x2(_x2), y2(_y2)
 33     {
 34         if (x1 != x2) 
 35         {
 36             k = (y2 - y1 + 0.0) / (x2 - x1 + 0.0);
 37             b = y1 - k * x1;
 38         }
 39         else
 40             k = 0.0, b = -1E13;
 41     }
 42     int x1, y1, x2, y2;
 43     double k, b;
 44     double give(const int &x) const
 45     {
 46         if (x == x1)
 47             return y1 * 1.0;
 48         else
 49             if (x == x2)
 50                 return y2 * 1.0;
 51             else
 52                 return k * (x * 1.0) + b;
 53     }
 54 };
 55 
 56 #define LEFT  (segt[cur].l)
 57 #define RIGHT (segt[cur].r)
 58 #define MID   (segt[cur].mid)
 59 #define VAL   (segt[cur].val)
 60 #define LCH   (cur << 1)
 61 #define RCH   ((cur << 1) | 1)
 62 
 63 struct node
 64 {
 65     int l, r, mid;
 66     segment val;
 67 };
 68 
 69 struct Segment_Tree
 70 {
 71     node segt[Max_X << 2];
 72     void build_tree(const int&, const int&, const int&);
 73     void cover(const int&, const segment&);
 74     void insert(const int&, const int&, const int&, const segment&);
 75     double query(const int&, const int&);
 76 };
 77 Segment_Tree seg;
 78 
 79 void Segment_Tree::build_tree(const int &cur, const int &l, const int &r)
 80 {
 81     LEFT = l, RIGHT = r, MID = l + ((r - l) >> 1);
 82     if (l == r)
 83         return;
 84     build_tree(LCH, l, MID), build_tree(RCH, MID + 1, r);
 85 }
 86 
 87 void Segment_Tree::insert(const int &cur, const int &l, const int &r, const segment &val)
 88 {
 89     if (LEFT == l && RIGHT == r)
 90     {
 91         cover(cur, val);
 92         return;
 93     }
 94     if (r <= MID)
 95         insert(LCH, l, r, val);
 96     else
 97         if (l > MID)
 98             insert(RCH, l, r, val);
 99         else
100             insert(LCH, l, MID, val), insert(RCH, MID + 1, r, val);
101 }
102 
103 void Segment_Tree::cover(const int &cur, const segment &val)
104 {
105     if (LEFT == RIGHT)
106     {
107         if (val.give(LEFT) > VAL.give(LEFT))
108             VAL = val;
109         return;
110     }
111     double VAL_l(VAL.give(LEFT)), VAL_r(VAL.give(RIGHT));
112     double val_l(val.give(LEFT)), val_r(val.give(RIGHT));
113     if (val_l <= VAL_l && val_r <= VAL_r)
114         return;
115     if (VAL_l <= val_l && VAL_r <= val_r)
116     {
117         VAL = val;
118         return;
119     }
120     double VAL_m(VAL.give(MID + 1)), val_m(val.give(MID + 1));
121     if (val_l <= VAL_l)
122         if (val_m <= VAL_m)
123             cover(RCH, val);
124         else
125             cover(LCH, VAL), VAL = val;
126     else
127         if (VAL_m <= val_m)
128             cover(RCH, VAL), VAL = val;
129         else
130             cover(LCH, val);
131 }
132 
133 double Segment_Tree::query(const int &cur, const int &x)
134 {
135     if (LEFT == RIGHT)
136         return VAL.give(x);
137     if (x <= MID)
138         return max(VAL.give(x), query(LCH, x));
139     else
140         return max(VAL.give(x), query(RCH, x));
141 }
142 
143 int BIT[Max_X];
144 
145 inline int lowbit(const int &x)
146 {
147     return x & -x;
148 }
149 
150 void insert(int i, const int &v)
151 {
152     while (i <= 100000)
153         BIT[i] += v, i += lowbit(i);
154 }
155 
156 int query(int i)
157 {
158     int Ret(0);
159     while (i)
160         Ret += BIT[i], i -= lowbit(i);
161     return Ret;
162 }
163 
164 int N, M;
165 double Record[Max_X];
166 
167 void insert(int x1, int y1, int x2, int y2)
168 {
169     if (x1 > x2)
170         swap(x1, x2), swap(y1, y2);
171     if (x1 == x2)
172     {
173         if (x1 >= 1 && x1 <= 100000)
174         {
175             Record[x1] = max(Record[x2], max(y1 * 1.0, y2 * 1.0));
176             insert(x1, +1), insert(x1 + 1, -1);
177         }
178         return;
179     }
180     int l, r;
181     l = max(1, x1), r = min(100000, x2);
182     if (l <= r)
183         seg.insert(1, l, r, segment(x1, y1, x2, y2)), insert(l, +1), insert(r + 1, -1);
184 }
185 
186 void init()
187 {
188     Get_Val(N), Get_Val(M);
189     seg.build_tree(1, 1, 100000);
190     for (int x = 1;x <= 100000;++x)
191         Record[x] = -1E13;
192     int x1, y1, x2, y2;
193     while (N--)
194     {
195         Get_Val(x1), Get_Val(y1), Get_Val(x2), Get_Val(y2);
196         insert(x1, y1, x2, y2);
197     }
198 }
199 
200 void work()
201 {
202     int op, x0, x1, y1, x2, y2;
203     while (M--)
204     {
205         Get_Val(op);
206         if (op == 0)
207         {
208             Get_Val(x1), Get_Val(y1), Get_Val(x2), Get_Val(y2);
209             insert(x1, y1, x2, y2);
210         }
211         else
212         {
213             Get_Val(x0);
214             if (query(x0))
215                 printf("%lf\n", max(Record[x0], seg.query(1, x0)));
216             else
217                 printf("0\n");
218         }
219     }
220 }
221 
222 int main()
223 {
224     init();
225     work();
226     return 0;
227 }
Day2T3

 

以上是关于2017雅礼省选集训做题记录的主要内容,如果未能解决你的问题,请参考以下文章

HNOI2015省选集训题

[北京省选集训2019]生成树计数

兔子的晚会 2016Vijos省选集训 day1

股神小L 2016Vijos省选集训 day1

LUOGU 5296: [北京省选集训2019]生成树计数 Gauss+Matrix-tree

2017雅礼集训 Day1