Lomsat gelral
で\(1 \)ツリーのルートを有している\(N- \)ノードを、各ノードが色を有し、各色(ツリー内の各サブツリーの最も要求にカラーコードの数を有しています同じ数、番号及び需要)の場合。
\(N \ 10 ^ 5 \)
問題の解決策
ツリーのテンプレートのタイトルのDSU。
暴力は、それはその後、その後、CNT配列を空にし、答えを得るために、再びサブツリーを、それを掃き、この点を列挙することで、実際には非常に簡単です。
我々は、それは、そのような最後の空のように、いくつかの有用な作業を行っている親は少ない子を数えることができますので、実際に、それは、彼の親のために使用することができることがわかります。
我々は可能な限り最大のサブツリーが消去されていない場合、重い木の断面の息子、彼の息子は、重い消去されませんありたいです。
そのような点は、それが光息子サブツリーにある場合にのみ、そう統計点がせいぜいであった場合に先祖カウントされる\()O(\ログN \) 回。総時間複雑\(O(N \ N-ログ)\) 。
#include<bits/stdc++.h>
#define co const
#define il inline
template<class T> T read(){
T x=0,w=1;char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*w;
}
template<class T>il T read(T&x){
return x=read<T>();
}
using namespace std;
typedef long long LL;
co int N=100001;
int n,val[N];
vector<int> e[N];
int fa[N],siz[N],son[N];
void dfs1(int x,int fa){
siz[x]=1;
for(unsigned i=0;i<e[x].size();++i){
int y=e[x][i];
if(y==fa) continue;
::fa[y]=x;
dfs1(y,x);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]]) son[x]=y;
}
}
LL ans[N];
int cnt[N],vis[N];
int maxc;LL sum;
void change(int x,int d){
cnt[val[x]]+=d;
if(d>0&&cnt[val[x]]>=maxc){
if(cnt[val[x]]>maxc) sum=0,maxc=cnt[val[x]];
sum+=val[x];
}
for(unsigned i=0;i<e[x].size();++i){
int y=e[x][i];
if(y==fa[x]||vis[y]) continue;
change(y,d);
}
}
void dfs2(int x,int use){
for(unsigned i=0;i<e[x].size();++i){
int y=e[x][i];
if(y==fa[x]||y==son[x]) continue;
dfs2(y,0);
}
if(son[x]) dfs2(son[x],1),vis[son[x]]=1;
change(x,1),ans[x]=sum;
if(son[x]) vis[son[x]]=0;
if(!use) change(x,-1),maxc=sum=0;
}
int main(){
read(n);
for(int i=1;i<=n;++i) read(val[i]);
for(int i=1,x,y;i<n;++i){
read(x),read(y);
e[x].push_back(y),e[y].push_back(x);
}
dfs1(1,0);
dfs2(1,0);
for(int i=1;i<=n;++i) printf("%lld ",ans[i]);
return 0;
}
アルパの手紙、マークツリーとMehrdadのDokhtar-koshパス
いずれかの(1 \)\ドットルート付きツリー、各側は小文字有する\を(A \ SIM V \) 。パスを定義する場合は良好であり、再配置後のこのパス上のすべての小文字は、パリンドローム配列を構成することができる場合にのみ。
最長の良いパスルートにするサブツリー内の各ポイントに探しています。
\(N \ 10 ^ 5 \)
問題の解決策
並び替えにはパリンドローム配列を形成することができる場合は、奇妙な文字が1まで表示されます。
まず、文字がある(C \)\の正しい値を定義縁、\(2 ^ C \)を。
そのような経路があれば良好であり、それは排他的論理和ビットであり、そのパスにおける場合のみ\(1 \)数は超えていない\(1 \)を。
サブツリーのある点での処理、オープンバレルは、示される場合\([I] \ f)はルートXORへのパスを表しする(Iは\)\最大深さ点を算出する。同様に点線の方法であることができます回答やアップデートバレル。
そして、ツリー上のDSUを設定し、この質問が解決されます。時間複雑\(O(N \ N-ログ)\) 。
#include<bits/stdc++.h>
#define co const
#define il inline
template<class T> T read(){
T x=0,w=1;char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*w;
}
template<class T>il T read(T&x){
return x=read<T>();
}
using namespace std;
co int N=500000+5;
int n,nx[N],to[N],val[N];
int siz[N],son[N],dep[N];
int pos[N],dfn,id[N],lst[N];
void dfs1(int x){
siz[x]=1,id[pos[x]=++dfn]=x;
for(int y=to[x];y;y=nx[y]){
dep[y]=dep[x]+1,val[y]=val[y]^val[x];
dfs1(y);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]]) son[x]=y;
}
lst[x]=dfn;
}
int f[1<<22],ans[N];
void dfs2(int x,int use){
for(int y=to[x];y;y=nx[y])
if(y!=son[x]) dfs2(y,0),ans[x]=max(ans[x],ans[y]);
if(son[x]) dfs2(son[x],1),ans[x]=max(ans[x],ans[son[x]]);
// cerr<<x<<" ans="<<ans[x]<<endl;
if(f[val[x]]) ans[x]=max(ans[x],f[val[x]]-dep[x]);
for(int i=0;i<22;++i)if(f[val[x]^(1<<i)])
ans[x]=max(ans[x],f[val[x]^(1<<i)]-dep[x]);
f[val[x]]=max(f[val[x]],dep[x]);
// cerr<<x<<" ans="<<ans[x]<<endl;
for(int y=to[x];y;y=nx[y])if(y!=son[x]){
for(int i=pos[y];i<=lst[y];++i){
int z=id[i];
if(f[val[z]]) ans[x]=max(ans[x],f[val[z]]+dep[z]-(dep[x]<<1));
for(int j=0;j<22;++j)if(f[val[z]^(1<<j)])
ans[x]=max(ans[x],f[val[z]^(1<<j)]+dep[z]-(dep[x]<<1));
}
for(int i=pos[y];i<=lst[y];++i){
int z=id[i];
f[val[z]]=max(f[val[z]],dep[z]);
}
}
// cerr<<x<<" ans="<<ans[x]<<endl;
if(!use) for(int i=pos[x];i<=lst[x];++i) f[val[id[i]]]=0;
}
int main(){
read(n);
for(int i=2;i<=n;++i){
int fa=read<int>();char ch=getchar();
nx[i]=to[fa],to[fa]=i,val[i]=1<<(ch-'a');
}
dfs1(1);
dfs2(1,0);
for(int i=1;i<=n;++i) printf("%d ",ans[i]);
return 0;
}