zoukankan      html  css  js  c++  java
  • [HAOI2016] 地图

    给定一个仙人掌,每个点有一家拉面店,售卖油腻程度为 (a_i) 的拉面,油腻程度相同的拉面称作同一种拉面。有 (q) 个询问,每次问从点 (x) 开始,不经过所有从 (x)(1) 号点简单路径上的边,能够访问到的所有点中,油腻程度 (leq y) 且品尝次数为奇数或偶数的拉面有多少种。

    Solution

    建圆方树,则问题转化为查询某点为根的子树内,出现次数为奇数或偶数,且颜色编号不大于给定值的颜色总数

    在圆方树上对所有圆点跑出 DFS 序,则子树统计转化为区间统计

    考虑莫队套值域分块,用 (cnt[i]) 记录离散化后值为 (i) 的颜色的出现次数,同时维护 (sum[i][0/1]) 表示编号为 (i) 的块中出现次数为偶数或奇数的颜色的种类数,注意把 (0) 特判掉

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 500005;
    map<int,int> mp;
    int n,m,q,lim,val[N],ind,limv;
    int getbel(int x) {
        return x/lim + 1;
    }
    int getbelv(int x) {
        return x/limv + 1;
    }
    
    struct query {
        int l,r,ty,y,id;
        bool operator < (const query &b) {
            if(getbel(l)==getbel(b.l)) return r<b.r;
            else return getbel(l)<getbel(b.l);
        }
    };
    
    namespace solver {
        int a[N],cnt[N],sum[N][2],ans[N];
        query s[N];
        void add(int x) {
            if(cnt[x]==0) sum[getbelv(x)][1]++;
            else if(cnt[x]&1) sum[getbelv(x)][1]--, sum[getbelv(x)][0]++;
            else sum[getbelv(x)][1]++, sum[getbelv(x)][0]--;
            cnt[x]++;
        }
        void dec(int x) {
            cnt[x]--;
            if(cnt[x]==0) sum[getbelv(x)][1]--;
            else if(cnt[x]&1) sum[getbelv(x)][1]++, sum[getbelv(x)][0]--;
            else sum[getbelv(x)][1]--, sum[getbelv(x)][0]++;
        }
        int getans(int x,int ty) {
            int ans=0;
            for(int i=1;i<getbelv(x);i++) ans+=sum[i][ty];
            for(int i=getbelv(x)*limv-limv;i<=x;i++) if(cnt[i]%2==ty&&cnt[i]) ans++;//!
            return ans;
        }
        void solve() {
            for(int i=1;i<=n;i++) mp[a[i]]++;
            for(auto i=mp.begin();i!=mp.end();i++) i->second=++ind, val[ind]=i->first;
            for(int i=1;i<=n;i++) a[i]=mp[a[i]];
            lim=sqrt(n);
            limv=sqrt(ind);
            sort(s+1,s+q+1);
            int l=1,r=0;
            for(int i=1;i<=q;i++) {
                while(r<s[i].r) add(a[++r]);
                while(l>s[i].l) add(a[--l]);
                while(r>s[i].r) dec(a[r--]);
                while(l<s[i].l) dec(a[l++]);
                auto it=mp.upper_bound(s[i].y);
                --it;
                ans[s[i].id]=getans(it->second,s[i].ty);
            }
            for(int i=1;i<=q;i++) cout<<ans[i]<<endl;
        }
    }
    
    namespace cactus {
        int cnt;
        vector<int> G[N], g[N * 2];
        int dfn[N], low[N], dfc, s[N], t[N], ind, stk[N], tp, a[N];
    
        void Tarjan(int u) {
            low[u] = dfn[u] = ++dfc;
            stk[++tp] = u;
            for (auto v : G[u]) {
                if (!dfn[v]) {
                    Tarjan(v);
                    low[u] = min(low[u], low[v]);
                    if (low[v] == dfn[u]) {
                        ++cnt;
                        for (int x = 0; x != v; --tp) {
                            x = stk[tp];
                            g[cnt].push_back(x);
                            g[x].push_back(cnt);
                        }
                        g[cnt].push_back(u);
                        g[u].push_back(cnt);
                    }
                }
                else low[u] = min(low[u], dfn[v]);
            }
        }
    
        void dfs(int p) {
            if(p<=n) s[p]=++ind; else s[p]=-1;//!
            for(int q:g[p]) if(s[q]==0) dfs(q);
            if(p<=n) t[p]=ind;
        }
    
        void solve() {
            cin>>n>>m;
            for(int i=1;i<=n;i++) cin>>a[i];
            for(int i=1;i<=m;i++) {
                int t1,t2;
                cin>>t1>>t2;
                G[t1].push_back(t2);
                G[t2].push_back(t1);
            }
            cnt = n;
            for (int u = 1; u <= n; ++u)
                if (!dfn[u]) Tarjan(u), --tp;
            dfs(1);
            cin>>q;
            for(int i=1;i<=n;i++) solver::a[s[i]]=a[i];
            for(int i=1;i<=q;i++) {
                int ty,x,y;
                cin>>ty>>x>>y;
                solver::s[i]={s[x],t[x],ty,y,i};
            }
        }
    }
    
    signed main() {
        ios::sync_with_stdio(false);
        cactus::solve();
        solver::solve();
    }
    
    
  • 相关阅读:
    无向图判断割点
    C
    连通图 求至少有给几个点信息才能传遍全图,至少添加几条边才能使全图联通
    线段树区间更新(set暴力)
    A
    辗转相除法(数学推理)
    Python List index()方法
    Python List extend()方法
    Python List count()方法
    Python List append()方法
  • 原文地址:https://www.cnblogs.com/mollnn/p/12404084.html
Copyright © 2011-2022 走看看