《洛谷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\n",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\n",ans[i] <= 1 ? "Yes" : "No");
    system("pause");
}
View Code

 

posted @ 2020-09-03 15:35  levill  阅读(224)  评论(0编辑  收藏  举报