首页 > 其他分享 >20221111_T1B_线段树优化建图/并查集

20221111_T1B_线段树优化建图/并查集

时间:2022-11-11 15:35:26浏览次数:38  
标签:return T1B int 查集 u1 20221111 一个点 建图 inline

题意

给定一个字符串,其中只有 a 和 b,现在一个字符能够跳到与之中间 a 的个数范围在 \([l,r]\) 的东西。

题解

赛时得分:100/100

对于一个东西,显然如果将能相互到达连边,那么一个点肯定是向后面和前面的一个区间连边的。

这个区间得到,我们可以通过二分解决。

普通是暴力枚举这些东西然后用并查集合并。这样复杂度显然是 \(\mathcal{O}(n^2)\) 的。我们思考线段树优化建图(毕竟是一个区间)

看如下图建边过程

image

image

image

这样建图之后我们满足了建图复杂度是 \(\mathcal{O}(n\log n)\) 但是怎么查询呢?

我们发现我们建边只会是一个点向另一个点或者是方框建边,那么我们固定一个点,另一个点向上跳,看看有没有固定在一起的就好了。

所以总时间复杂度 \(\mathcal{O}(n\log n)\)。

题解是 \(\mathcal{O}(n)\) 是根据 \(k\) 的大小分类。我不会,爬了。

出题人说这方法只有 45 分,但是卡不掉。

代码

#include <bits/stdc++.h>
using namespace std;
template <typename T>inline void read(T& t){t=0; register char ch=getchar(); register int fflag=1;while(!('0'<=ch&&ch<='9')) {if(ch=='-') fflag=-1;ch=getchar();}while(('0'<=ch&&ch<='9')){t=t*10+ch-'0'; ch=getchar();} t*=fflag;}
template <typename T,typename... Args> inline void read(T& t, Args&... args) {read(t);read(args...);}
const int N = 2e6 + 10, inf = 0x3f3f3f3f;

int n, l, r, q, sum[N], lc[N << 2], rc[N << 2], id[N << 2];
string st;
int fa[N << 2], rnk[N << 2];
bool biao[N << 2];

inline int findf(int x) {
    if(fa[x] == x) return x;
    else return fa[x] = findf(fa[x]);
}
inline void merge(int x, int y) {
    int fx = findf(x), fy = findf(y);
    if(fx == fy) return;
    if(rnk[fx] >= rnk[fy]) swap(fx, fy), swap(x, y);
    fa[fx] = fy; rnk[fy] += fx;
} 
inline bool check(int x, int y) {return findf(x) == findf(y);}
inline void build(int u, int l, int r) {
    // u 就是这个点的标号了
    lc[u] = l, rc[u] = r;
    if(l == r) {
        id[l] = u;
        return;
    }
    int mid = l + r >> 1;
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
inline void adde(int u, int l, int r, int idu) {
    if(l <= lc[u] && r >= rc[u]) {
        merge(u, idu);
        biao[u] = 1;
        return;
    }
    if(l > rc[u] || lc[u] > r) return;
    adde(u << 1, l, r, idu), adde(u << 1 | 1, l, r, idu);
}
inline bool Find(int u, int idu) {
    if(findf(u) == findf(idu)) return 1;
    else if(u != 1) return Find(u >> 1, idu);
    return 0;
}
inline bool upup(int u1, int u2) {
    if(u1 == 1) return 0;
    if(u1 != u2) return upup(u1 >> 1, u2 >> 1);
    else if(biao[u1]) return 1;
    else return upup(u1 >> 1, u2 >> 1);
}
inline void Down(int u) {
    if(lc[u] == rc[u]) return;
    if(fa[u] != u) merge(u, u << 1), merge(u << 1, u << 1 | 1);
    Down(u << 1), Down(u << 1 | 1);
    return;
}

int main() {
    freopen("virtual.in", "r", stdin);
    freopen("virtual.out", "w", stdout);
    cin >> n >> l >> r;
    cin >> st;
    st = '*' + st;
    for(int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + (st[i] == 'a');
    build(1, 1, n);
    for(int i = 1; i <= (n << 2); ++i) fa[i] = i, rnk[i] = 1;
    for(int i = 1; i <= n; ++i) {
        int Le = lower_bound(sum + 1, sum + n + 1, l + sum[i - 1]) - sum, Ri = upper_bound(sum + 1, sum + n + 1, r + sum[i - 1]) - sum - 1;
        if(Le <= Ri) adde(1, Le, Ri, id[i]);
        Le = lower_bound(sum, sum + n + 1, sum[i] - r) - sum + 1, Ri = lower_bound(sum, sum + n + 1, sum[i] - l + 1) - sum;
        if(Le <= Ri) adde(1, Le, Ri, id[i]);
    }
    // }
    Down(1);
    read(q);
    for(int i = 1; i <= q; ++i) {
        int x, y;
        read(x, y);
        if(Find(id[x], id[y]) || Find(id[y], id[x])) puts("Yes");
        else puts("No");
    } 
    return 0;
}

标签:return,T1B,int,查集,u1,20221111,一个点,建图,inline
From: https://www.cnblogs.com/Mercury-City/p/16880593.html

相关文章

  • C# =>实用详解(20221111)
    =>主要有两方面的作用,一个限制属性状态,另一个简化匿名委托和Lambda用法一:定义只读属性 publicclassManPeople{publicstringSex=>"男"; publicstringNam......
  • 1. 演进、环境与资源-20221111
    C++11也叫2.0了解:之前std:tr1的内容都已经放到std内了搜索:   :Gcc:unix家族,MinGW:windows家族   选择支持C++11还是14:【右击项目】–【选择属性】–【C/C++......
  • [A202211110354]
    [A202211110354](2022,南开大学)设\(x_n=\displaystyle\sum_{k=0}^n{\frac{1}{k!}}\),\(n=1,2,\cdots\),求极限\[\lim_{n\rightarrow\infty}\left(\frac{\lnx_n}{\sqr......
  • [A202211110303]
    [A202211110303](2022,同济大学)已知\(\{a_n\}\)是一个实数列,\(0<|\lambda|<1\).证明:\(\displaystyle\lim_{n\rightarrow\infty}a_n=a\)的充要条件是\[\lim_{n\rig......
  • POJ-1417(带权并查集+01背包+回溯)
    TrueLiars题目描述:Peter有一个王国。在这个王国里,一共有2种人,即诚实人和撒谎人。诚实人永远说真话,撒谎人永远说假话。可惜的是,Peter只记得诚实人的数量和撒谎人的数量......
  • 并查集
    [NOI2001]食物链题目描述动物王国中有三类动物\(A,B,C\),这三类动物的食物链构成了有趣的环形。\(A\)吃\(B\),\(B\)吃\(C\),\(C\)吃\(A\)。现有\(N\)个动物,以\(......
  • I-图的分割(二分+并查集)
    图的分割题目大意:给你n个点,m条边的图,没有重环和自环,所有的点都联通可以通过删除几条边使得整个图变成两个联通子图求删除的边中最大边权的最小值解题思路:看到“最......
  • 【模板】并查集 DSU
    postedon2021-09-1215:49:52|under模板|source0x00模板并查集维护的是这样一个问题:\(n\)个点,初始时每个点自己一个集合。\({\ttmerge}(x,y)\):合并\(x,y\)......
  • 啊哈之 最小生成树,并查集,快速排序
    6924113513463564236457121349132//输出19packagecom.company;importjava.io.FileInputStream;importjava.text.CollationKey......
  • D. Secret Passwords_并查集
    D.SecretPasswords题目大意给一堆字符串,两个串有一个字母一样就算等效。问所有字符串里有几个不等效的。思路并查集入门题llfa[N];llfind(llx){ returnfa[x......