zoukankan      html  css  js  c++  java
  • ACM ICPC China final G Pandaria

    ACM ICPC China final G Pandaria



    题意:给一张(n)个点(m)条边的无向图,(c[i])代表点(i)的颜色,每条边有一个权值
    现在有q个询问如下
    u w代表从点u出发,每次只能走权值不超过w的边,经过的颜色中次数最多的是哪种颜色,若有多种,输出编号最小的。
    $ 1<=n<=1e5$
    $ 1<=m,q<=2e5$
    $ 1<=c_i<=n$
    $ 1<=w<=1e6$
    ps:强制在线

    思路: 把边从小到大排序,依次合并,现在就是如何维护每个连通块的答案了。
    用主席树维护区间最大值和合并操作,查询就是二分最大值的最左位置
    如果这题不强制在线的话,那么我们可以把查询按w从小大排序,模拟过去即可
    强制在线就多了一些东西,考虑合并的过程,其实是一颗自底向上的树,越往上边权越大
    前面主席树已经算出每个结点的答案,如何找到要查询的历史版本,通过pa数组自底向上倍增即可

    #include<bits/stdc++.h>
    #define P pair<int,int>
    #define LL long long
    #define ls(i) seg[i].lc
    #define rs(i) seg[i].rc
    using namespace std;
    
    const int mod = 1e9 + 7;
    const int N = 1e5 + 1;
    const int M = 2 * N;
    const int maxn = 3 * N;
    const int maxh = 25;
    int n, m,tott;
    int c[N];
    int ans[maxn];
    struct Tree{
        int ls, rs, w;
    }tree[maxn];
    struct node{
        int lc,rc,cnt;
    }seg[maxn * maxh];///主席树维护的区间的最大值,二分查询最大值所在的最左位置
    int root[maxn * maxh];
    struct Edge{
        int u, v, w;
        Edge(){};
        bool operator<(const Edge&rhs)const{
            return w < rhs.w;
        }
    }e[M];
    void pushup(int rt){
        seg[rt].cnt = max(seg[ls(rt)].cnt,seg[rs(rt)].cnt);
    }
    void update(int &rt,int l,int r,int pos,int val){
        seg[++tott] = seg[rt];
        rt = tott;
        if(l == r){
            seg[rt].cnt += val;
            return ;
        }
        int m = (l + r) >> 1;
        if(pos <= m) update(ls(rt),l,m,pos,val);
        else update(rs(rt),m+1,r,pos,val);
        pushup(rt);
    }
    int query(int rt,int l,int r){
        if(l == r) return l;
        int m = (l + r) >> 1;
        if(seg[ls(rt)].cnt >= seg[rs(rt)].cnt) return query(ls(rt),l,m);
        return query(rs(rt),m+1,r);
    }
    int Merge(int rt1,int rt2,int l,int r){
        if(!rt1 || !rt2) return rt1 + rt2;///最多只有n个点保证了合并的复杂度科学
        if(l == r){
            seg[rt1].cnt += seg[rt2].cnt;
            return rt1;
        }
        int m = l + r >> 1;
        ls(rt1) = Merge(ls(rt1),ls(rt2),l,m);
        rs(rt1) = Merge(rs(rt1),rs(rt2),m+1,r);
        pushup(rt1);
        return rt1;
    }
    int pa[maxn][maxh];
    int Find(int x){
        return pa[x][0] == x?x:pa[x][0] = Find(pa[x][0]);
    }
    int ask(int u,int w){ ///倍增找接近的历史版本的答案
        for(int i = maxh - 1;i >= 0;i--) if(pa[u][i] && tree[pa[u][i]].w <= w) u = pa[u][i];
        return ans[u];
    }
    int main(){
    
        int T, cas = 1;
        cin>>T;
        while(T--){
            scanf("%d%d",&n,&m);
            tott = 0;
            for(int i = 1;i <= n;i++) {
                    scanf("%d",c + i);
                    root[i] = root[0];
                    update(root[i],1,n,c[i],1);
                    pa[i][0] = i;
                    tree[i].w = 0; ///叶子结点权值为0
                    ans[i] = query(root[i],1,n);
            }
            for(int i = 0;i < m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
            int tot = n;
            sort(e, e + m);
            for(int i = 0;i < m;i++){
                int u = Find(e[i].u), v = Find(e[i].v), w = e[i].w;
                if(u == v) continue;
                tree[++tot].w = w;///合并得到新的父结点
                tree[tot].ls = u, tree[tot].rs = v;///两个孩子
                pa[tot][0] = pa[u][0] = pa[v][0] = tot;
                root[tot] = Merge(root[u],root[v],1,n);
                ans[tot] = query(root[tot],1,n);
            }
            for(int i = n + 1;i <= tot;i++) pa[tree[i].ls][0] = pa[tree[i].rs][0] = i;///前面为路径压缩的用途,现在改为上一级祖先用途
            for(int i = 1;i <= tot;i++) pa[i][0] = pa[i][0] == i?0:pa[i][0];
            for(int i = 1;i < maxh;i++)
                for(int j = 1;j <= tot;j++) pa[j][i] = pa[pa[j][i-1]][i-1];
            int q, last = 0, u, w;
            printf("Case #%d:
    ",cas++);
            scanf("%d",&q);
            while(q--){
                scanf("%d%d",&u,&w);
                u ^= last, w ^= last;
                printf("%d
    ",last = ask(u,w));
            }
        }
        return 0;
    }
    
    

  • 相关阅读:

    链表
    队列
    稀疏数组
    SQL——流程控制
    SQL——存储过程与函数
    SOA
    MVC模式
    《一线架构师实践指南》--阅读笔记三
    《一线架构师实践指南》-阅读笔记二
  • 原文地址:https://www.cnblogs.com/jiachinzhao/p/7260494.html
Copyright © 2011-2022 走看看