zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    必须掌握的八个DOS命令
    实况足球8 功略简解
    开始→运行→命令集锦
    必须掌握的八个DOS命令
    对称加密算法之DES算法
    让你的Linux像黑客帝国的画面一样炫酷
    古典密码之凯撒密码and换位密码
    用eclipse写jsp报以下错误
    mysql安装后,过一段时间,在命令行无法启动
    sql 日期函数
  • 原文地址:https://www.cnblogs.com/Cw-trip/p/4731543.html
Copyright © 2011-2022 走看看