欢迎光临散文网 会员登陆 & 注册

CF竞赛题目讲解_Tree Requests(树上启发式合并)

2022-05-19 11:00 作者:Clayton_Zhou  | 我要投稿


// https://codeforces.com/problemset/problem/570/D

 

#include "stdafx.h"

//#include <bits/stdc++.h>


#include <algorithm> 

#include <vector> 

using namespace std;


#define ll long long

#define pii pair<int, int>

const int maxn = 5e5 + 10;


//1为根 有根树 带点权 点权a到z 询问rt子树 深度为d的这层节点 点权重排能否构成回文串

 

//暴力 -> 树上启发式合并

vector<int> g[maxn];

int cnt[maxn][30];//深度为i 字母为j的个数

int son[maxn],siz[maxn],dep[maxn];

char col[maxn]="\0zacccd";

vector<pii> q[maxn];

bool ans[maxn];


int L[maxn],V[maxn],T=0;//  dfs 顺序编号


//轻重链剖分

void dfs(int rt) 

{

siz[rt]=1;

V[L[rt]=++T]=rt;

for(int &i:g[rt]) 

{

dep[i]=dep[rt]+1;

dfs(i);

if(siz[i] > siz[son[rt]]) son[rt]=i;

siz[rt]+=siz[i];

}

}

bool check(int d) //check深度为d  字母分布情况

{

int odd=0;//奇数个数

for(int i=1;i<=26;i++) 

{

odd+=(cnt[d][i]&1);

}

return odd<=1;

}



void dfs2(int rt,bool ok) 

{

for(auto i:g[rt]) 

{

if(i==son[rt]) continue;

dfs2(i,0);

}

if(son[rt]) dfs2(son[rt],1);


for(auto k:g[rt]) 

{

if(k==son[rt]) continue;

for (int i=0; i<siz[k]; i++) 

{

int id=col[V[L[k]+i]]-'a'+1;

cnt[dep[V[L[k]+i]]][id]+=1;

}

}

int id=col[rt]-'a'+1;

cnt[dep[rt]][id]+=1;

for(auto i:q[rt]) 

{   //  i.second 为查询标号, i.first 为查询深度

ans[i.second]=check(i.first);

if(!ok) //是轻儿子 clear

for (int i=0; i<siz[rt]; i++) 

{

id=col[V[L[rt]+i]]-'a'+1;

cnt[dep[V[L[rt]+i]]][id]-=1;

}

}

int n,m;

int main()

{

n=6,m=5;

// scanf("%d %d",&n,&m);,


int fa;

int faa[8]={1 ,1, 1, 3 ,3};

for(int i=2;i<=n;i++) 

{

//int fa;scanf("%d",&fa);

fa=faa[i-2];

g[fa].push_back(i);

}


//scanf("%s",col+1);

dep[1]=1;

dfs(1);


int qq[32][2]={

1 ,1,

3 ,3,

4, 1,

6, 1,

1, 2};

for(int i=1;i<=m;i++) 

{

int u,d;

//scanf("%d %d",&u,&d);

u=qq[i-1][0];

d=qq[i-1][1];

q[u].push_back(make_pair (d,i));

}

dfs2(1,1);

for(int i=1;i<=m;i++) 

if(ans[i]) puts("Yes");

else puts("No");

return 0;

}


CF竞赛题目讲解_Tree Requests(树上启发式合并)的评论 (共 条)

分享到微博请遵守国家法律