zoukankan      html  css  js  c++  java
  • 数据结构

    数据结构


    单调栈

    https://xlor.cn/2019/4/2019nanchang/


    笛卡尔树

    Equivalent Prefixes-前缀笛卡尔树

    序列u,v 对于([1,ans])上所有的([L,R])((1<=L<=R<=ans<=n))

    都满足(RMQ(u,L,R)=RMQ(v,L,R))

    (max(ans));

    分析:考虑判断两个序列的前缀笛卡尔树是否相等

    注意,如果前缀笛卡尔树相等,则可以判断每一个栈深都相同,想想为什么?、

    #include <bits/stdc++.h>
    #include<stdint.h>
    #define int long long
    #define scan(n) scanf("%lld", &(n))
    #define scann(n, m) scanf("%lld%lld", &(n), &(m))
    #define scannn(a, b, c) scanf("%lld%lld%lld", &(a), &(b), &(c))
    #define prin(n) printf("%lld", (n))
    #define pb push_back
    #define mp make_pair
    #define ms(a) memset(a, 0, sizeof(a))
    #define fo(i, a, b) for (int i = (a); i <= (b); i++)
    #define ro(i, a, b) for (int i = (a); i >= (b); i--)
    const int inf = 0x3f3f3f3f;
    using namespace std;
    const int maxn = 1e5+100;
    int n;
    int a[maxn],b[maxn];
    int s1[maxn],s2[maxn];
    int32_t main() {
        while(scan(n)!=EOF){
            fo(i,1,n)scan(a[i]);
            fo(i,1,n)scan(b[i]);
            int head1=1,head2=1,tail1=1,tail2=1;
            s1[head1]=s2[head2]=inf;
            int maxpos=1;
            fo(i,1,n){
                while(head1<=tail1&&s1[tail1]>a[i])tail1--;
                while(head2<=tail2&&s2[tail2]>b[i])tail2--;
                if(tail1!=tail2)break;
                s1[++tail1]=a[i],s2[++tail2]=b[i];
                maxpos=i;
            }
            cout<<maxpos<<endl;
        }
        return 0;
    }
    

    笛卡尔树习题

    http://acm.hdu.edu.cn/showproblem.php?pid=6305

    https://blog.csdn.net/zhaiqiming2010/article/details/80245872


    Bitset

    #include<bits/stdc++.h>
    using namespace std;
    
    bitset<5> b, a;
    int main() {
        cout << b << endl; //00000
    
        b.set(2);
        cout << b << endl;//00100
    
        a.set(3);
        cout << a << endl;//01000
    
        b ^= a;//(00100)^(01000)
        cout << b << endl;//01100
    
        b.reset(3);//00100
        cout << b << endl;
    
        b.flip();//11011
        cout << b << endl;
    }
    

    LCA

    [CF1304E]1-Trees and Queries

    https://codeforces.com/contest/1304/problem/E

    给一棵树,每次查询时在x和y之间加一条边,然后问在a和b之间是否存在一条可以重复走的路径且这条路径的长度为k

    如果不走x和y的那条连边,那么a到b之间的路径长度为a与b的最短路径+2i,因为重复走的边对答案的贡献一定是偶数长度,只有走了x到y的那条连边,贡献为1,可以改变路径的奇偶性,枚举两种情况即可

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 2e5 + 100;
    int head[maxn], to[maxn * 2], nxt[maxn * 2], d[maxn * 2], tot;
    int n, m;
    void add(int x, int y, int w){
        to[++tot] = y; nxt[tot] = head[x]; d[tot] = w; head[x] = tot;
    }
    int dp[maxn][20], dep[maxn], dis[maxn];
    void dfs(int u, int fa){
        dp[u][0] = fa; dep[u] = dep[fa] + 1;
        for (int i = head[u]; i; i = nxt[i]){
            int v = to[i];
            if (v == fa) continue;
            dis[v] = dis[u] + d[i];
            dfs(v, u);
        }
    }
    void init(){
        memset(dp, 0, sizeof(dp));
        dep[0] = dis[0] = 0;
        dfs(1, 0); 
        for (int j = 1; j < 20; j++) 
            for (int i = 1; i <= n; i++) 
                dp[i][j] = dp[dp[i][j - 1]][j - 1];
    }
    int qlca(int x, int y){
        if (dep[x] < dep[y]) swap(x, y);
        int tmp = dep[x] - dep[y];
        for (int i = 0; tmp; i++, tmp >>= 1)
            if (tmp & 1) x = dp[x][i];
        if (x == y) return x;
        for (int i = 19; i >= 0; i--){
            if (dp[x][i] != dp[y][i]){
                x = dp[x][i]; y = dp[y][i];
            }
        }
        return dp[x][0];
    }
    int dist(int x,int y) {
        int u = qlca(x, y);
        int ans =  dis[x] + dis[y] - 2*dis[u];
        return dis[x] + dis[y] - 2*dis[u];
    }
    int main() {
        scanf("%d", &n);
        for (int i = 1; i <= n-1;i++) {
            int x, y;
            scanf("%d%d", &x, &y);
            add(x, y, 1);
            add(y, x, 1);
        }
        init();
        int q;
        scanf("%d", &q);
        while(q--) {
            int a, b, x, y,k;
            scanf("%d%d%d%d%d", &x, &y, &a, &b, &k);
            int d = dist(a, b);
            if(k>=d&&(k-d)%2==0) {
                printf("YES
    ");
                continue;
            }
            else {
                d = dist(a,x)+dist(b,y)+1;
                if(k>=d&&(k-d)%2==0) {
                    printf("YES
    ");
                    continue;
                }
                d = dist(a,y)+dist(b,x)+1;
                if(k>=d&&(k-d)%2==0) {
                    printf("YES
    ");
                    continue;
                }
            }
            printf("NO
    ");
        }
    }
    

    树状数组

    Codeforces1324DPair of Topics

    https://codeforces.com/contest/1324/problem/D

    给定(a,b)序列,求有多少对(i<j)(a_i+a_j>b_i+b_j)

    解法1:按照值从大到小插入

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6 + 5;
    int a[maxn];
    int b[maxn];
    int c[maxn];
    struct Node
    {
        int v, index;
        bool operator<(const Node& b) const {
            if(v==b.v) {
                return index <b.index;//注意这里!!
            }
            return v < b.v;  //从小到大排序 
    	}
    }node[maxn];
    int n;
    void add(int i)
    {
    	while(i<=n*2)
    	{
    		c[i]++;
    		i+=i&(-i);	
    	}
    }
    int sum(int i)
    {
    	int res=0;
    	while(i>0)
    	{
    		res+=c[i];
    		i-=i&(-i);
    	}
    	return res;
    }
    vector<int> v;
    int main() {
        scanf("%d", &n);
        for(int i=1;i<=n;i++) {
            scanf("%d", &a[i]);
        }
        for(int i=1;i<=n;i++) {
            scanf("%d", &b[i]);
        }
        for (int i = 1; i <= n;i++) {
            node[i].v = a[i] - b[i];
            node[i].index = i;
            node[i + n].v = b[i] - a[i];
            node[i + n].index = i + n;
        }
        long long ans = 0;
        sort(node + 1, node + 1 + 2 * n);
        for (int i = 2*n; i >=1;i--) {
            int id = node[i].index;
            int v = node[i].v;
            if(id<=n) {
                add(node[i].index);
                continue;
            }
            if(v<0)
                ans--;
            ans += sum(id - n);
        }
     
        cout<<ans<<endl;
    }
    

    解法2:按照序列顺序从小到大

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 2e5 + 100;
    int a[maxn], b[maxn], c[maxn * 2];
    int lowbit(int x) {
        return x & (-x);
    }
    
    void add(int i,int d) {
        while(i<maxn*2) {
            c[i] += d;
            i += lowbit(i);
        }
    }
    
    int query(int i) {
        int ret = 0;
        while(i>0) {
            ret += c[i];
            i -= lowbit(i);
        }
        return ret;
    }
    
    vector<int> v;
    
    int main() {
        int n;
        scanf("%d", &n);
        for(int i=1;i<=n;i++) {
            scanf("%d", &a[i]);
        }
        for (int i = 1; i <= n;i++) {
            scanf("%d", &b[i]);
        }
        for (int i = 1; i <= n;i++) {
            v.push_back(a[i] - b[i]);
            v.push_back(b[i] - a[i]);
        }
        long long ans = 0;
        sort(v.begin(), v.end());
        for (int i = 1;i<=n;i++) {
            int x = b[i] - a[i];
            int y = a[i] - b[i];
            int id = upper_bound(v.begin(), v.end(), x) - v.begin() + 1;
            int id2 = upper_bound(v.begin(), v.end(), y) - v.begin() + 1;
            ans += (i - 1 - query(id));
            add(id2, 1);
        }
        cout << ans << endl;
    }
    

    打一顿!!不用树状数组

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 2e5 + 100;
    vector<int> v;
    int a[maxn],b[maxn];
    
    int main() {
        int n;
        scanf("%d", &n);
        for (int i = 1; i <= n;i++) {
            scanf("%d", &a[i]);
        }
        for (int i = 1; i <= n;i++) {
            scanf("%d", &b[i]);
            v.push_back(a[i] - b[i]);
        }
        sort(v.begin(), v.end());
        long long ans = 0;
        for (int i = 1; i <= n;i++) {
            int id = upper_bound(v.begin(), v.end(), b[i] - a[i]) - v.begin();
            ans += (n  - id);
            if(a[i]-b[i]>b[i]-a[i])
                ans--;
        }
        ans /= 2;
        cout << ans << endl;
    }
    

    [CF1325C] Ehab and Path-etic MEXS

    https://codeforces.com/contest/1325/problem/C

    给一棵树的边附上0~n-2的权值,使得Mex(u,v)的最大值最小

    思路:只需要考虑0,1,2的情况

    ​ 对于所有不经过0的路径,mex = 0

    ​ 对于所有不经过12,但经过0的路径,mex = 12

    ​ 这样就可以满足所有情况

    #include<bits/stdc++.h>
    using namespace std;
     
    const int maxn = 1e5 + 5;
    struct node{
        int to, id;
    };
    vector<node> e[maxn];
    int x[maxn], y[maxn];
    int vis[maxn];
    int ans[maxn];
    int l, r;
    void dfs(int u,int fa) {
        int sz = e[u].size();
        for (int i = 0; i < sz;i++) {
            int v = e[u][i].to;
            int id = e[u][i].id;
            if(v==fa||vis[id])
                continue;
            ans[id] = l++;
        }
        for (int i = 0;i<sz;i++) {
            int v = e[u][i].to;
            int id = e[u][i].id;
            if(v==fa||vis[id])
                continue;
            vis[id]++;
            dfs(v, u);
        }
    }
    int main() {
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n - 1;i++) {
            scanf("%d %d", &x[i], &y[i]);
            e[x[i]].push_back((node){y[i], i});
            e[y[i]].push_back((node){x[i], i});
        }
        l = 0, r = n - 2;
        int d = 0;
        int m = 0;
        for (int i = 1; i <= n;i++) {
            int sz = e[i].size();
            if(sz>d) {
                d = sz;
                m = i;
            }
        }
     
        dfs(m, -1);
        for (int i = 0; i < n-1;i++) {
            printf("%d
    ", ans[i]);
        }
        return 0;
    }
    

    [CF1325F]Ehab's Last Theorem

    令t为ceil(sqrt(n))

    解法一:考虑DFS树的原理,如果从(u)(v),经过的不是((u,v))这条边,说明先前存在另一条路径使得(u)(v),那么此时可以形成一个环,具体的见这篇文章: https://codeforces.com/blog/entry/68138

    并且!如果一个点的dfs子树中所有的点都不能与它满足构成长度大于t的环这个条件,也就是情况2,那么这个点就可以存在于独立点集中

     if(!vis[u]) {
            for(int v:e[u]) {
                vis[v] = 1;
            }
        }
    

    u必然不会存在与一个长度大于t的环当中,那么它必然在独立集里,则把它的连边全部标记起来。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5 + 100;
    int t;
    int dep[maxn];
    int f[maxn],vis[maxn];
    vector<int> e[maxn];
    void dfs(int u,int fa) {
        for(int v:e[u]) {
            if(!dep[v]) {
                dep[v] = dep[u] + 1;
                f[v] = u;
                dfs(v, u);
            } 
            else {
                if(dep[v]-dep[u]+1>=t) {
                    printf("2
    ");
                    int len = dep[v] - dep[u] + 1;
                    printf("%d
    ", len);
                    int cnt = 0;
                    while(v) {
                        if(cnt==len)
                            break;
                        cnt++;
                        printf("%d ", v);
                        v = f[v];
                    }
                    exit(0);
                }
            }
        }
        if(!vis[u]) {
            for(int v:e[u]) {
                vis[v] = 1;
            }
        }
    }
    int main() {
        int n, m;
        scanf("%d%d", &n, &m);
        t = ceil(sqrt(n));
        for (int i = 1; i <= m;i++) {
            int x, y;
            scanf("%d%d", &x, &y);
            e[x].push_back(y);
            e[y].push_back(x);
        }
        dep[1] = 1;
        dfs(1, 0);
        printf("1
    ");
        int cnt = 0;
        for (int i = 1; i <= n;i++) {
            if(cnt==t)
                break;
            if(!vis[i]) {
                printf("%d ", i);
                cnt++;
            }
        }
    }
    

    解法2:

    一个结论:如果一张图里的每个点的度数都大于(d),那么必然存在一个环,长度为(d+1)

    在寻找环的过程中将所有度数小于(t-1)的点的邻边都删掉,这个点作为独立集的备选

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 2e5 + 100;
    set<pair<int,int> > s;
    vector<int> v[maxn];
    bool del[maxn];
    int deg[maxn],occ[maxn];
    void remove(int x)
    {
        if (del[x])
        return;
        s.erase({deg[x],x});
        del[x]=1;
        for (int u:v[x])
        {
            if (!del[u])
            {
                s.erase({deg[u],u});
                deg[u]--;
                s.insert({deg[u],u});
            }
        }
    }
    
    int main()
    {
        int n, m,sq;
        scanf("%d%d",&n,&m);
        sq = ceil(sqrt(n));
        while (m--)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            v[a].push_back(b);
            v[b].push_back(a);
            deg[a]++;
            deg[b]++;
        }
    
        for (int i=1;i<=n;i++)
        s.insert({deg[i],i});
        vector<int> ans;
        while (!s.empty())
        {
            auto p=*s.begin();
            s.erase(s.begin());
            if (p.first+1>=sq)//度数大于等于sq-1
            {
                printf("2
    ");
                vector<int> d({p.second});
                occ[p.second]=1;
                while (1)
                {
                    pair<int,int> nex(1e9,0);
                    for (int u:v[d.back()])
                    {
                        if (!del[u])
                        nex=min(nex,make_pair(occ[u],u));
                    }
                    if (nex.first)
                    {
                        printf("%d
    ",(int)d.size()-nex.first+1);
                        for (int i=nex.first-1;i<d.size();i++)
                        printf("%d ",d[i]);
                        return 0;
                    }
                    d.push_back(nex.second);
                    occ[nex.second]=d.size();
                }
            }
            //度数小于sq-1
            ans.push_back(p.second);
            remove(p.second);//删除所有邻边
            for (int u:v[p.second])//双向删除
            remove(u);
        }
        printf("1
    ");
        for (int i=0;i<sq;i++)
        printf("%d ",ans[i]);
    }
    

    [CF1139C] Edgy Tree

    https://codeforces.com/contest/1139/problem/C

    题意:一棵树,且需要构建长度为k的序列,序列中相邻两点的路径一定经过"黑边",节点可以重复

    思路:"黑边"不加入连通块,将"红边"的各个连通块的大小找出来,减去这一部分构造的长度为k的序列

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 2e5 + 100;
    vector<int> e[maxn];
    int vis[maxn];
    const long long mod = 1e9 + 7;
    #define add(x, y) (x + y) % mod;
    int dfs(int u,int fa) {
        int sz = e[u].size();
        long long ret = 1;
        vis[u]++;
        for (int i = 0; i < sz;i++) {
            int v = e[u][i];
            if(v==fa||vis[v]){
                continue;
            }
            ret += dfs(v, u);
        }
        return ret;
    }
    long long qpow(long long x,int k) {
        long long ret = 1;
        while(k) {
            if(k&1)
                ret = ret * x % mod;
            x = x * x % mod;
            k >>= 1;
        }
        return ret;
    }
    int main() {
        int n, k;
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n - 1;i++) {
            int x, y, w;
            scanf("%d%d%d", &x, &y, &w);
            if(!w) {
                e[x].push_back(y);
                e[y].push_back(x);
            }
        }
        long long sum = 0;
        for (int i = 1; i <= n; i++) {
            if (vis[i])
                continue;
            long long cnt = dfs(i, -1);
            long long x = qpow(cnt, k);
            sum = add(sum, x);
        }
        long long ans = qpow(n, k);
        ans = (ans - sum + mod) % mod;
        cout << ans << endl;
    }
    
  • 相关阅读:
    doraemon的python 函数(整理了下笔记)感觉自己棒棒哒
    Mybatis系列教材 (七)- 动态SQL
    Mybatis系列教材 (六)- 基础
    Mybatis系列教材 (五)- 基础
    Mybatis系列教材 (四)- 基础
    Mybatis系列教材 (三)- 基础
    Mybatis系列教材 (二)- 基础
    Mybatis系列教材 (一)- 入门教程
    SSH系列教材 (七)- 整合-注解方式
    SSH系列教材 (六)- 使用注解方式配置事务管理
  • 原文地址:https://www.cnblogs.com/guaguastandup/p/12585240.html
Copyright © 2011-2022 走看看