CF708C Centroids
1.如果节点u不是重心,那么它有且仅有一个size v ≥n/2(重儿子),则要在重儿子中找一个大小为s的树,满足2*(size v -s)≤n,2*s≤n
2.假设是一棵以重心为根的有根树,则对于节点u≠root,其重儿子大小为n-size u,即断掉u与其fa的连边后的另一棵树,那么问题转化为:对于每一个 uu 判断上边有无一棵大小满足不在 u 的子树内且 n/2−size u ≤S≤n/2 的树。
3.具体实现:维护两棵权值树状数组t1和t2
t1[i]:维护全局的大小小于 i 的个数
t2[i]:维护当前扫过点的子树中大小小于 i 的个数
对于一个u,其子树内满足条件的数量就是扫完u之后t2的变化量,需要将其减去
代码实现如下:
#include <bits/stdc++.h>
using namespace std;
const int N=400005;
int n,E,root,siz[N],ans[N],t1[N],t2[N];
int pnt[N*2],nxt[N*2],head[N];
void add_e(int u,int v) {
pnt[++E]=v,nxt[E]=head[u],head[u]=E;
}
void prp(int u,int f) {
siz[u]=1;
bool ok=1;
for(int i=head[u];i;i=nxt[i]) {
int v = pnt[i];
if(v == f) continue;
prp(v,u);
siz[u] += siz[v];
if(siz[v] > n/2) ok=0;
}
if(n-siz[u] > n/2) ok=0;
if(ok) root=u, ans[u]=1;
}
void add(int a[],int x,int v) {if(x<=0) return;for(++x;x<=n+1;x+=x&-x) a[x]+=v;}
int ask(int a[],int x) {
if(x <= 0) return 0;
int res = 0;
for(++x;x;x-=x&-x) res += a[x];
return res;
}
void solve(int u,int fa) {
int t=0;
add(t1,siz[fa],-1);
add(t1,n-siz[u],1);
if(ans[u] == 0) {
t += ask(t1,n/2);
t -= ask(t1,(n-2*siz[u]+1)/2-1);
t += ask(t2,n/2);
t -= ask(t2,(n-2*siz[u]+1)/2-1);
}
add(t2,siz[u],1);
for(int i=head[u];i;i=nxt[i]) {
int v = pnt[i];
if(v==fa) continue;
solve(v,u);
}
add(t1,siz[fa],1);
add(t1,n-siz[u],-1);
if(ans[u] == 0) {
t -= ask(t2,n/2);
t += ask(t2,(n-2*siz[u]+1)/2-1);
if(t > 0) ans[u]=1;
}
}
int main(){
scanf("%d",&n);
for(int u,v,i=1;i<n;i++) {
scanf("%d%d",&u,&v);
add_e(u,v), add_e(v,u);
}
prp(1,0);
prp(root,0);
for(int i=0;i<=n;i++) add(t1,siz[i],1);
solve(root,0);
for(int i=1;i<=n;i++) printf("%d ",ans[i]);
return printf("\n"),0;
}
P3668 Modern Art 2 G
1.记录每一种颜色的起始点以及终点,可以想象,如果染色次数要最少,那么最外一层的颜色要最先涂
2.可以想象出一个栈,当前点的的起始位置加入栈,如果这一段有颜色不同于这个点的,就不可能,碰到当前点的终止位置,就出栈,最大染色次数就是栈最大的size,可以画个图试一下,当size 变化为 1 2 3 2 1 时,两边明显是可同时进行的,所以答案应该只要记录最大值
0是不填颜色,所以它的出栈位置记录为n+1,先让0入栈,并让其最后出栈,但是这并不会记录进染色次数,所以答案要-1
最后代码呈上:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,a[maxn],book[maxn],ans,top;
int s[maxn],e[maxn],sta[maxn];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
if(!s[a[i]]) s[a[i]]=i;
e[a[i]]=i;
}
e[0]=n+1;a[n+1]=0;
for(int i=0,x;i<=n+1;++i){
x=a[i];
if(i==s[x]) sta[++top]=x,ans=max(ans,top);
if(x!=sta[top]){
printf("-1");
return 0;
}
if(i==e[x]) top--;
}
printf("%d",ans-1);
return 0;
}