• 《洛谷CF570D Tree Requests》


    挺好的一道题:

    首先,可以dsu on tree做。

    这里的精髓就是当奇数个数的点 <= 1时,就能构成。(这里对2取模了。)

    那么可以用异或操作来实现对二取模。同时异或两次也就相当于没有做异或操作。

    所以也可以用异或来清空轻儿子的贡献。

    那么就需要状压每个字母的状态。因为只有26个字母。

    这里还有个问题,就是查询要怎么办。

    我们可以把查询挂到点上,然后统计完后,去查询每个操作。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,int> pii;
    const int N = 5e5+5;
    const int M = 1e5+5;
    const LL Mod = 199999;
    #define rg register
    #define pi acos(-1)
    #define INF 1e9
    #define CT0 cin.tie(0),cout.tie(0)
    #define IO ios::sync_with_stdio(false)
    #define dbg(ax) cout << "now this num is " << ax << endl;
    namespace FASTIO{
        inline LL read(){
            LL x = 0,f = 1;char c = getchar();
            while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
            while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
            return x*f;
        }
        void print(int x){
            if(x < 0){x = -x;putchar('-');}
            if(x > 9) print(x/10);
            putchar(x%10+'0');
        }
    }
    using namespace FASTIO;
    void FRE(){/*freopen("data1.in","r",stdin);
    freopen("data1.out","w",stdout);*/}
    
    int n,m,val[N],ssize[N],son[N],Son,dep[N],ans[N];
    int cnt[N];
    struct Query{int id,d;};
    vector<Query> vec[N];
    vector<int> G[N];
    char s[N];
    void dfs(int u,int fa)
    {
        ssize[u] = 1,dep[u] = dep[fa]+1;
        for(auto v : G[u])
        {
            if(v == fa) continue;
            dfs(v,u);
            ssize[u] += ssize[v];
            if(ssize[v] > ssize[son[u]]) son[u] = v;
        }
    }
    void slove(int u,int fa)
    {
        cnt[dep[u]] ^= (1<<val[u]);
        for(auto v : G[u])
        {
            if(v == fa || v == Son) continue;
            slove(v,u);
        }
    }
    int check(int d)
    {
        int sum = 0;
        for(rg int i = 0;i < 26;++i) sum += ((cnt[d]>>i)&1);
        return sum;
    }
    void dfs1(int u,int fa,int opt)
    {
        for(auto v : G[u])
        {
            if(v == fa || v == son[u]) continue;
            dfs1(v,u,0);
        }
        if(son[u]) dfs1(son[u],u,1),Son = son[u];
        slove(u,fa);
        Son = 0;
        for(auto t : vec[u])
        {
            ans[t.id] = check(t.d);
        }
        if(opt == 0) slove(u,fa);
    }
    int main()
    {
        n = read(),m = read();
        for(rg int i = 2;i <= n;++i)
        {
            int par;par = read();
            G[i].push_back(par);
            G[par].push_back(i);
        }
        dfs(1,0);
        scanf("%s",s);
        int len = strlen(s);
        for(rg int i = 0;i < len;++i) val[i+1] = s[i]-'a';
        for(rg int i = 1;i <= m;++i)
        {
            int v,h;v = read(),h = read();
            vec[v].push_back(Query{i,h});
        }
        dfs1(1,0,0);
        for(rg int i = 1;i <= m;++i) printf("%s
    ",ans[i] <= 1 ? "Yes" : "No");
       // system("pause");
    }
    View Code

    同时,这里的话也可以用线段树合并来解决。

    我们对每个点的开n个位置来记录每个点的深度状压的值。

    然后线段树动态开点去合并即可。

    那么查询的时候就是个单点查询某个深度的状压值了。

    注意合并到边界要特判。这里debug了半天.

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,int> pii;
    const int N = 5e5+5;
    const int M = 1e5+5;
    const LL Mod = 199999;
    #define rg register
    #define pi acos(-1)
    #define INF 1e9
    #define CT0 cin.tie(0),cout.tie(0)
    #define IO ios::sync_with_stdio(false)
    #define dbg(ax) cout << "now this num is " << ax << endl;
    namespace FASTIO{
        inline LL read(){
            LL x = 0,f = 1;char c = getchar();
            while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
            while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
            return x*f;
        }
        void print(int x){
            if(x < 0){x = -x;putchar('-');}
            if(x > 9) print(x/10);
            putchar(x%10+'0');
        }
    }
    using namespace FASTIO;
    void FRE(){/*freopen("data1.in","r",stdin);
    freopen("data1.out","w",stdout);*/}
    
    int n,m,rt[N],top = 0,val[N],dep[N],ans[N];
    struct Node{int L,r,val;}node[N*20];
    struct Query{int id,d;};
    vector<int> G[N];
    vector<Query> vec[N];
    char s[N];
    int build(int L,int r,int x,int tmp)
    {
        int idx = ++top;
        if(L == r)
        {
            node[idx].val ^= (1<<tmp);
            return idx;
        }
        int mid = (L+r)>>1;
        if(mid >= x) node[idx].L = build(L,mid,x,tmp);
        else node[idx].r = build(mid+1,r,x,tmp);
        node[idx].val = node[node[idx].L].val ^ node[node[idx].r].val;
        return idx;
    }
    int Merge(int x,int y,int L,int r)
    {
        if(x == 0) return y;
        if(y == 0) return x;
        if(L == r)
        {
            node[x].val ^= node[y].val;
            return x;
        }
        int mid = (L+r)>>1;
        node[x].L = Merge(node[x].L,node[y].L,L,mid);
        node[x].r = Merge(node[x].r,node[y].r,mid+1,r);
        if(L == r) node[x].val = node[x].val ^ node[y].val;
        node[x].val = node[node[x].L].val ^ node[node[x].r].val;
        return x;
    }
    int query(int x,int L,int r,int idx)
    {
        if(L == r) return node[idx].val;
        int mid = (L+r)>>1;
        if(mid >= x) return query(x,L,mid,node[idx].L);
        else return query(x,mid+1,r,node[idx].r);
    }
    void dfs(int u,int fa)
    {
        dep[u] = dep[fa]+1;
        for(auto v : G[u]) if(v != fa) dfs(v,u);
    }
    int check(int x)
    {
        int sum = 0;
        for(rg int i = 0;i < 26;++i) sum += ((x>>i)&1);
        return sum;
    }
    void dfs1(int u,int fa)
    {
        for(auto v : G[u])
        {
            if(v == fa) continue;
            dfs1(v,u);
            rt[u] = Merge(rt[u],rt[v],1,n);
        }
        for(auto t : vec[u]) ans[t.id] = check(query(t.d,1,n,rt[u]));
    }
    int main()
    {
        n = read(),m = read();
        for(rg int i = 2;i <= n;++i) 
        {
            int par;par = read();
            G[par].push_back(i);
            G[i].push_back(par);
        }
        dfs(1,0);
        scanf("%s",s);
        int len = strlen(s);
        for(rg int i = 0;i < len;++i) val[i+1] = s[i]-'a';
        for(rg int i = 1;i <= n;++i) rt[i] = build(1,n,dep[i],val[i]);
        for(rg int i = 1;i <= m;++i)
        {
            int v,h;v = read(),h = read();
            vec[v].push_back(Query{i,h});
        }
        dfs1(1,0);
        for(rg int i = 1;i <= m;++i) printf("%s
    ",ans[i] <= 1 ? "Yes" : "No");
        system("pause");
    }
    View Code
  • 相关阅读:
    小酌一下:pipenv 基本用法
    sql2008使用您对无法重新创建的表进行了更改或者启用了“阻止保存重新创建表的更改”
    Join操作基本:外连接、自然连接、内连接
    用dataReader获取datetime类型完整精度的时间字串
    c# MesageBox
    判断当前时间是否在一个时间段内
    c# 根据当前时间获取,本周,本月,本季度,月初,月末,各个时间段
    sql Convert函数
    c# MD5方法总结
    wml跳转
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/13607888.html
Copyright © 2020-2023  润新知