• 570D Codeforces Round #316 (Div. 2) D(dfs序,时间戳,二分


    题目:一棵树上每个节点有个字符值,询问每个节点的深度为h的子节点的字符是否能组成一个回文串。

    思路:首先是奇妙的dfs序和时间戳,通过记录每个节点的dfs进出时间,可以发现某个节点的子节点的进出时间均在该节点的进出时间范围内(这是很直观的dfs的性质),这样可以把树形结构转变为线性结构,方便进行各种处理。dfs一遍处理时间戳,每个节点的深度,并记录每个深度的节点都有哪些,此时每个深度的节点就是排好序的。然后对于一个询问,可以利用二分查找确定子节点在该层的哪一段。对于每一层,预先处理每个字符的前缀和,就可以做到O(1)查询区间数量。由于这题只要求奇偶性,故只需要记录01,又因为字符集为26,可以直接用int类型压位。

    ps:二分直接用的stl的,结果反而写得像一坨翔一样= =

    #include <bits/stdc++.h>
    #define pb push_back
    #define se second
    #define fs first
    #define sq(x) (x)*(x)
    #define eps 0.000000001
    #define LB lower_bound
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> P;
    const int maxv=5e5+3000;
    int n,m;
    vector<int> G[maxv];
    vector<int> D[maxv];
    vector<int> num[maxv];
    int deep[maxv];
    int in[maxv],out[maxv];
    char s[maxv];
    int clo=0;
    void dfs(int v,int d,int f){
        D[d].pb(v);
        deep[v]=d;
        in[v]=++clo;
        for(int i=0;i<G[v].size();i++){
            int u=G[v][i];
            if(u==f) continue;
            dfs(u,d+1,v);
        }
        out[v]=++clo;
    }
    void cul(){
        for(int i=1;i<=n;i++){
            if(D[i].size()==0){
                break;
            }
            num[i].pb(1<<(s[D[i][0]-1]-'a'));
            for(int j=1;j<D[i].size();j++){
                int c=s[D[i][j]-1]-'a';
                num[i].pb(num[i].back()^(1<<c));
            }
        }
    }
    bool cmpl(const int &va,const int &vb){return in[va]<vb;}
    bool cmpr(const int &va,const int &vb){return out[va]<vb;}
    int cas=0;
    int main(){
    //    freopen("/home/files/CppFiles/in","r",stdin);
        cin>>n>>m;
        for(int i=2;i<=n;i++){
            int p;
            scanf("%d",&p);
            G[p].pb(i);
        }
        scanf("%s",s);
        dfs(1,1,-1);
        cul();
        while(m--){
            int v,h;
            scanf("%d%d",&v,&h);
            int l=in[v],r=out[v],sd=h;
            if(deep[v]>h){
                puts("Yes");
                continue;
            }
            vector<int>::iterator itl=LB(D[sd].begin(),D[sd].end(),l,cmpl);
            vector<int>::iterator itr=LB(D[sd].begin(),D[sd].end(),r,cmpr);
            if(itr!=D[sd].begin()&&((itr!=D[sd].end()&&out[*itr]>r)||itr==D[sd].end())) itr--;
            if(itl!=D[sd].end()&&itr!=D[sd].end()&&in[*itl]>=l&&out[*itr]<=r){
                int dl=itl-D[sd].begin();
                int dr=itr-D[sd].begin();
                int nu=(dl>0?num[sd][dl-1]:0);
                if(nu^num[sd][dr]){
                    if(__builtin_popcount(nu^num[sd][dr])<2)
                        puts("Yes");
                    else{
                        puts("No");
                    }
                }else{
                    puts("Yes");
                }
            }else{
                puts("Yes");
                continue;
            }
        }
    }
    View Code
  • 相关阅读:
    django中的objects.get和objects.filter方法的区别
    Django之CSRF
    Django之include本质
    django中的FBV和CBV
    HTTP协议【详解】——经典面试题
    Python中的魔法函数__repr__和__str__的实质性区别
    浅谈CSS中的百分比
    深入理解定时器系列第一篇——理解setTimeout和setInterval
    Javascript学习
    HTML中块级元素和行内元素的总结和区分。
  • 原文地址:https://www.cnblogs.com/Cw-trip/p/4731543.html
Copyright © 2020-2023  润新知