1. 程式人生 > 實用技巧 >《洛谷CF570D Tree Requests》

《洛谷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