杂题小记(2023.02.27)更好的阅读体验戳此进入LG-P3865 【模板】ST 表LG-P3293 [SCOI2016]美味题面SolutionCodeLG-P5490 【模板】扫描线题面SolutionCodeLG-P1856 [IOI1998] [USACO5.5] 矩形周长Picture题面SolutionCodeLG-P1972 [SDOI2009] HH的项链题面SolutionCodeLG-P3582 [POI2015] KIN题面SolutionCodeLG-P4551 最长异或路径题面SolutionCodeUPD
别问我为什么又写一遍 ST 表模板,问就是太久没写了重写一遍试试。。。
给定序列
考虑对于一般的无偏移的此类异或最大值可以用 01Trie 实现,对于此题我们首先考虑 01Trie 上每个节点的本质,即对于一个表示了第
xxxxxxxxxx86123
4567891011
12using namespace std;13
14mt19937 rnd(random_device{}());15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}16bool rnddd(int x){return rndd(1, 100) <= x;}17
18typedef unsigned int uint;19typedef unsigned long long unll;20typedef long long ll;21typedef long double ld;22
2324
25template < typename T = int >26inline T read(void);27
28int N, M;29
30class SegTree{31private:32 struct Node{Node *ls, *rs; int cnt;};33 34public:35 Node* root[210000];36 Node* Build(int gl = 0, int gr = LIM){37 if(gl == gr)return new Node{npt, npt, 0};38 return new Node{Build(gl, MID), Build(MID + 1, gr), 0};39 }40 SegTree(void){root[0] = Build();}41 Node* Create(int val, Node* lstp, int gl = 0, int gr = LIM){42 Node* p = lstp ? new Node{lstp->ls, lstp->rs, lstp->cnt + 1} : new Node{npt, npt, 1};43 if(gl != gr){44 if(val <= MID)p->ls = Create(val, p->ls, gl, MID);45 else p->rs = Create(val, p->rs, MID + 1, gr);46 }return p;47 }48 int Query(int l, int r, Node* &p, int gl = 0, int gr = LIM){49 if(!p)p = new Node{npt, npt, 0};50 if(l <= gl && gr <= r)return p->cnt;51 if(gr < l || gl > r)return 0;52 return Query(l, r, p->ls, gl, MID) + Query(l, r, p->rs, MID + 1, gr);53 }54}st;55
56int main(){57 N = read(), M = read();58 for(int i = 1; i <= N; ++i)st.root[i] = st.Create(read(), st.root[i - 1]);59 while(M--){60 int base = read(), exc = read(), l = read(), r = read();61 int cur(0);62 for(int i = 20; i >= 0; --i){63 auto [rngl, rngr] = base & (1 << i) ? pair{cur - exc, cur + (1 << i) - 1 - exc} : pair{cur + (1 << i) - exc, cur + (1 << (i + 1)) - 1 - exc};64 int cnt = rngl < 0 && rngr < 0 ? 0 : st.Query(rngl, rngr, st.root[r]) - st.Query(rngl, rngr, st.root[l - 1]);65 cur += (bool(base & (1 << i)) ^ (bool)cnt) << i;66 }printf("%d\n", cur ^ base);67 }68 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);69 return 0;70}71
72template < typename T >73inline T read(void){74 T ret(0);75 int flag(1);76 char c = getchar();77 while(c != '-' && !isdigit(c))c = getchar();78 if(c == '-')flag = -1, c = getchar();79 while(isdigit(c)){80 ret *= 10;81 ret += int(c - '0');82 c = getchar();83 }84 ret *= flag;85 return ret;86}求二维平面平行坐标轴矩形面积并。
大概是突然发现以前居然都只是口糊的,没正经写过扫描线。。。
按照🧠里的思路写了一下,写成的是带 Pushdown 的标准线段树,然后调来调去改了半天,然后才发现这玩意应该写成类似标记永久化的形式,对于满的区间直接打标记就完事了,然后因为查询有且只有总的查询,所以只维护一个朴素的 Pushup 即可,也不需要用到永久化的合并标记等。
xxxxxxxxxx92123
4567891011
12using namespace std;13
14mt19937 rnd(random_device{}());15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}16bool rnddd(int x){return rndd(1, 100) <= x;}17
18typedef unsigned int uint;19typedef unsigned long long unll;20typedef long long ll;21typedef long double ld;22
2324
25template < typename T = int >26inline T read(void);27
28int N;29ll ans(0);30struct Line{int l, r; int h; int val;};31basic_string < Line > lines;32basic_string < int > vdata;33
34class SegTree{35private:36 int len[210000 << 2], lz[210000 << 2];37 38 39 40public:41 void Pushup(int p, int gl, int gr){42 if(!lz[p])len[p] = gl == gr ? 0 : len[LS] + len[RS];43 else len[p] = d(gr + 1) - d(gl);44 }45 void Modify(int l, int r, int val, int p = 1, int gl = 1, int gr = N - 1){46 if(l <= gl && gr <= r)return lz[p] += val, Pushup(p, gl, gr);47 if(l <= MID)Modify(l, r, val, LS, gl, MID);48 if(r >= MID + 1)Modify(l, r, val, RS, MID + 1, gr);49 Pushup(p, gl, gr);50 }51 int Query(void){return len[1];}52}st;53
54int main(){55 N = read();56 for(int i = 1; i <= N; ++i){57 int x1 = read(), y1 = read(), x2 = read(), y2 = read();58 vdata += {x1, x2};59 lines += {Line{x1, x2, y1, 1}, Line{x1, x2, y2, -1}};60 }N = lines.size();61 sort(vdata.begin(), vdata.end());62 vdata.erase(unique(vdata.begin(), vdata.end()), vdata.end());63 for(auto &line : lines){64 line.l = distance(vdata.begin(), next(lower_bound(vdata.begin(), vdata.end(), line.l)));65 line.r = distance(vdata.begin(), next(lower_bound(vdata.begin(), vdata.end(), line.r))) - 1;66 }sort(lines.begin(), lines.end(), [](const Line &a, const Line &b)->bool{return a.h < b.h;});67 for(auto it = lines.begin(); it != lines.end(); advance(it, 1)){68 int curh = it->h;69 st.Modify(it->l, it->r, it->val);70 while(next(it) != lines.end() && next(it)->h == curh)71 advance(it, 1), st.Modify(it->l, it->r, it->val);72 if(next(it) != lines.end())ans += (ll)st.Query() * (next(it)->h - curh);73 }printf("%lld\n", ans);74 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);75 return 0;76}77
78template < typename T >79inline T read(void){80 T ret(0);81 int flag(1);82 char c = getchar();83 while(c != '-' && !isdigit(c))c = getchar();84 if(c == '-')flag = -1, c = getchar();85 while(isdigit(c)){86 ret *= 10;87 ret += int(c - '0');88 c = getchar();89 }90 ret *= flag;91 return ret;92}求二维平面内平行于坐标轴矩形的并的周长。
本来感觉就是一道很白给的题,但是写起来发现还是会有一些细节的,两处小错误调了好久。
首先是可以有一个更容易的写法的,不需要维护一大堆东西,直接考虑对于一般的扫描线,有贡献的情况仅为原来不存在边的地方有边了或者原来有边的地方删掉了,于是我们可以直接考虑维护本次查询的有边的长度,与上次查询的长度做差,绝对值即为贡献。此时不难发现问题,对于一般的写法我们会将相同高度的合在一起处理,比如面积并,对于本题我们考虑一个矩形的上边与另一个的下边重合,就会发现少计算贡献了,对于这种也不难想到不合并相同高度的,分别处理,同时对于
xxxxxxxxxx112123
4567891011
12using namespace std;13
14mt19937 rnd(random_device{}());15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}16bool rnddd(int x){return rndd(1, 100) <= x;}17
18typedef unsigned int uint;19typedef unsigned long long unll;20typedef long long ll;21typedef long double ld;22
2324
25template < typename T = int >26inline T read(void);27
28int N;29int rN;30ll ans(0);31struct Line{int l, r; int h; int val;};32basic_string < Line > lines;33basic_string < int > vdata;34tuple < int, int, int, int > vals[5100];35
36class SegTree{37private:38 int len[11000 << 2], lz[11000 << 2];39 40 41 42public:43 void Pushup(int p, int gl, int gr){44 if(lz[p])len[p] = d(gr + 1) - d(gl);45 else len[p] = gl == gr ? 0 : len[LS] + len[RS];46 }47 void Modify(int l, int r, int val, int p = 1, int gl = 1, int gr = N - 1){48 if(l <= gl && gr <= r)return lz[p] += val, Pushup(p, gl, gr);49 if(l <= MID)Modify(l, r, val, LS, gl, MID);50 if(r >= MID + 1)Modify(l, r, val, RS, MID + 1, gr);51 Pushup(p, gl, gr);52 }53 int Query(void){return len[1];}54}st, st2;55
56int main(){57 rN = read();58 for(int i = 1; i <= rN; ++i){59 int x1 = read(), y1 = read(), x2 = read(), y2 = read();60 vals[i] = {x1, y1, x2, y2};61 vdata += {x1, x2};62 lines += {Line{x1, x2, y1, 1}, Line{x1, x2, y2, -1}};63 }N = lines.size();64 sort(vdata.begin(), vdata.end());65 vdata.erase(unique(vdata.begin(), vdata.end()), vdata.end());66 for(auto &line : lines){67 line.l = distance(vdata.begin(), next(lower_bound(vdata.begin(), vdata.end(), line.l)));68 line.r = distance(vdata.begin(), next(lower_bound(vdata.begin(), vdata.end(), line.r))) - 1;69 }sort(lines.begin(), lines.end(), [](const Line &a, const Line &b)->bool{return a.h == b.h ? a.val > b.val : a.h < b.h;});70 int lstlen(0);71 for(auto it = lines.begin(); it != lines.end(); advance(it, 1)){72 st.Modify(it->l, it->r, it->val);73 int curlen = st.Query();74 ans += abs(curlen - lstlen);75 lstlen = curlen;76 }vdata.clear(), lines.clear();77 for(int i = 1; i <= rN; ++i){78 auto [x1, y1, x2, y2] = vals[i];79 vdata += {y1, y2},80 lines += {Line{y1, y2, x1, 1}, Line{y1, y2, x2, -1}};81 }sort(vdata.begin(), vdata.end());82 vdata.erase(unique(vdata.begin(), vdata.end()), vdata.end());83 for(auto &line : lines){84 line.l = distance(vdata.begin(), next(lower_bound(vdata.begin(), vdata.end(), line.l)));85 line.r = distance(vdata.begin(), next(lower_bound(vdata.begin(), vdata.end(), line.r))) - 1;86 }sort(lines.begin(), lines.end(), [](const Line &a, const Line &b)->bool{return a.h == b.h ? a.val > b.val : a.h < b.h;});87 lstlen = 0;88 for(auto it = lines.begin(); it != lines.end(); advance(it, 1)){89 st2.Modify(it->l, it->r, it->val);90 int curlen = st2.Query();91 ans += abs(curlen - lstlen);92 lstlen = curlen;93 }printf("%lld\n", ans);94 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);95 return 0;96}97
98template < typename T >99inline T read(void){100 T ret(0);101 int flag(1);102 char c = getchar();103 while(c != '-' && !isdigit(c))c = getchar();104 if(c == '-')flag = -1, c = getchar();105 while(isdigit(c)){106 ret *= 10;107 ret += int(c - '0');108 c = getchar();109 }110 ret *= flag;111 return ret;112}给定序列,多组询问求区间
莫队复杂度无法通过,存在一个简单但很高妙的做法,考虑将询问离线按右端点排序,从
xxxxxxxxxx77123
4567891011
12using namespace std;13
14mt19937 rnd(random_device{}());15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}16bool rnddd(int x){return rndd(1, 100) <= x;}17
18typedef unsigned int uint;19typedef unsigned long long unll;20typedef long long ll;21typedef long double ld;22
23
24
25template < typename T = int >26inline T read(void);27
28int N, M;29int A[1100000];30int lst[1100000];31int ans[1100000];32
33class BIT{34private:35 int tr[1100000];36public:37 int lowbit(int x){return x & -x;}38 void Modify(int x, int v){while(x <= N)tr[x] += v, x += lowbit(x);}39 int Query(int x){int ret(0); while(x)ret += tr[x], x -= lowbit(x); return ret;}40}bit;41
42struct Query{int l, idx;};43basic_string < Query > r[1100000];44
45int main(){46 N = read();47 for(int i = 1; i <= N; ++i)A[i] = read();48 M = read();49 for(int i = 1; i <= M; ++i){50 int l = read();51 r[read()] += Query{l, i};52 }53 for(int i = 1; i <= N; ++i){54 if(lst[A[i]])bit.Modify(lst[A[i]], -1);55 bit.Modify(i, 1), lst[A[i]] = i;56 for(auto q : r[i])ans[q.idx] = bit.Query(i) - bit.Query(q.l - 1);57 }58 for(int i = 1; i <= M; ++i)printf("%d\n", ans[i]);59 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);60 return 0;61}62
63template < typename T >64inline T read(void){65 T ret(0);66 int flag(1);67 char c = getchar();68 while(c != '-' && !isdigit(c))c = getchar();69 if(c == '-')flag = -1, c = getchar();70 while(isdigit(c)){71 ret *= 10;72 ret += int(c - '0');73 c = getchar();74 }75 ret *= flag;76 return ret;77}给定序列
类似上一题,用线段树维护,每个点维护到当前
xxxxxxxxxx93123
4567891011
12using namespace std;13
14mt19937 rnd(random_device{}());15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}16bool rnddd(int x){return rndd(1, 100) <= x;}17
18typedef unsigned int uint;19typedef unsigned long long unll;20typedef long long ll;21typedef long double ld;22
23template < typename T = int >24inline T read(void);25
26int N, M;27int A[1100000];28int llst[1100000];29int lst[1100000];30ll w[1100000];31ll ans(0);32
33class SegTree{34private:35 ll mx[1100000 << 2], lz[1100000 << 2];36 37 38 39public:40 void Pushup(int p){41 mx[p] = max(mx[LS], mx[RS]);42 }43 void Pushdown(int p){44 if(!lz[p])return;45 lz[LS] += lz[p], lz[RS] += lz[p];46 mx[LS] += lz[p], mx[RS] += lz[p];47 lz[p] = 0;48 }49 void Modify(int l, int r, int val, int p = 1, int gl = 1, int gr = N){50 if(l <= gl && gr <= r)return mx[p] += val, lz[p] += val, void();51 Pushdown(p);52 if(l <= MID)Modify(l, r, val, LS, gl, MID);53 if(r >= MID + 1)Modify(l, r, val, RS, MID + 1, gr);54 Pushup(p);55 }56 ll QueryMax(int l, int r, int p = 1, int gl = 1, int gr = N){57 if(l <= gl && gr <= r)return mx[p];58 if(l > gr || gl > r)return 0;59 Pushdown(p);60 return max(QueryMax(l, r, LS, gl, MID), QueryMax(l, r, RS, MID + 1, gr));61 }62}st;63
64int main(){65 N = read(), M = read();66 for(int i = 1; i <= N; ++i)A[i] = read();67 for(int i = 1; i <= M; ++i)w[i] = read();68 for(int i = 1; i <= N; ++i){69 if(llst[A[i]])st.Modify(1, llst[A[i]], w[A[i]]);70 if(lst[A[i]])st.Modify(1, lst[A[i]], -2 * w[A[i]]);71 st.Modify(1, i, w[A[i]]);72 llst[A[i]] = lst[A[i]], lst[A[i]] = i;73 ans = max(ans, st.QueryMax(1, i));74 }printf("%lld\n", ans);75 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);76 return 0;77}78
79template < typename T >80inline T read(void){81 T ret(0);82 int flag(1);83 char c = getchar();84 while(c != '-' && !isdigit(c))c = getchar();85 if(c == '-')flag = -1, c = getchar();86 while(isdigit(c)){87 ret *= 10;88 ret += int(c - '0');89 c = getchar();90 }91 ret *= flag;92 return ret;93}给定带边权树,求树上异或和最大的路径。
考虑将树上根到每一个叶子节点的异或和记录并插进 01Trie,然后枚举刚才记录的每一个值在 01Trie 上查异或最大值然后取
xxxxxxxxxx98123
4567891011
12using namespace std;13
14mt19937 rnd(random_device{}());15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}16bool rnddd(int x){return rndd(1, 100) <= x;}17
18typedef unsigned int uint;19typedef unsigned long long unll;20typedef long long ll;21typedef long double ld;22
2324
25template < typename T = int >26inline T read(void);27
28class Trie{29private:30 struct Node{Node* son[2];};31 Node* root;32public:33 Trie(void){root = new Node{{npt, npt}};}34 void Insert(int val){35 auto cur = root;36 for(int i = LIM; i >= 0; --i){37 bool bit = val & (1 << i);38 if(!cur->son[bit])cur->son[bit] = new Node{{npt, npt}};39 cur = cur->son[bit];40 }41 }42 int QueryMax(int val){43 auto cur = root; int ans(0);44 for(int i = LIM; i >= 0; --i){45 bool bit = val & (1 << i);46 ans |= (((bool)cur->son[bit ^ 1] ^ bit) << i);47 cur = cur->son[bit ^ 1] ? cur->son[bit ^ 1] : cur->son[bit];48 }return ans ^ val;49 }50}trie;51
52int N;53int ans(0);54basic_string < int > vals;55
56struct Edge{57 Edge* nxt;58 int to;59 int val;60 OPNEW;61}ed[210000];62ROPNEW;63Edge* head[110000];64
65void dfs(int p = 1, int fa = 0, int cur = 0){66 trie.Insert(cur), vals += cur;67 for(auto i = head[p]; i; i = i->nxt)68 if(SON != fa)dfs(SON, p, cur ^ i->val);69}70
71int main(){72 N = read();73 for(int i = 1; i <= N - 1; ++i){74 int s = read(), t = read(), v = read();75 head[s] = new Edge{head[s], t, v};76 head[t] = new Edge{head[t], s, v};77 }dfs();78 for(auto v : vals)ans = max(ans, trie.QueryMax(v));79 printf("%d\n", ans);80 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);81 return 0;82}83
84template < typename T >85inline T read(void){86 T ret(0);87 int flag(1);88 char c = getchar();89 while(c != '-' && !isdigit(c))c = getchar();90 if(c == '-')flag = -1, c = getchar();91 while(isdigit(c)){92 ret *= 10;93 ret += int(c - '0');94 c = getchar();95 }96 ret *= flag;97 return ret;98}update-2023_02_27 初稿