CF620E New Year Tree 状压+线段树(+dfs序?)
借用学长的活:60种颜色是突破口(我咋不知道QAQ)
好像这几道都是线段树+dfs序??于是你可以把60种颜色压进一个long long 里,然后向上合并的时候与一下(太妙了~)
所以记得开long long (又调了一个半小时。。。打代码只花了20分钟???)
#include<cstdio> #include<iostream> #define ll long long #define R register int #define ls (tr<<1) #define rs (tr<<1|1) const int N=400010; using namespace std; inline ll g() { R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix; do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix; } int n,m,cnt,num; int vr[N<<1],nxt[N<<1],fir[N],dfn[N],sz[N],rw[N],w[N]; ll sum[N<<2]; bool tg[N<<2]; inline void add(int u,int v) {vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;} inline ll lbt(ll x) {return x&-x;} inline int ppc(ll x) {R ret=0; while(x) x-=lbt(x),++ret; return ret;} void dfs(int u) { sz[u]=1,dfn[u]=++num,rw[num]=u; for(R i=fir[u];i;i=nxt[i]) { R v=vr[i]; if(dfn[v]) continue; dfs(v); sz[u]+=sz[v]; } } inline void build(int tr,int l,int r) { if(l==r) {sum[tr]=1ll<<w[rw[l]]; return; } R md=(l+r)>>1; build(ls,l,md),build(rs,md+1,r); sum[tr]=sum[ls]|sum[rs]; } inline void spread(int tr) { if(tg[tr]) tg[tr]=false,sum[ls]=sum[rs]=sum[tr],tg[ls]=tg[rs]=true; } inline void update(int tr,int l,int r,int LL,int RR,int inc) { if(LL<=l&&r<=RR) {sum[tr]=1ll<<inc; tg[tr]=true; return ;} spread(tr); R md=(l+r)>>1; if(LL<=md) update(ls,l,md,LL,RR,inc); if(RR>md) update(rs,md+1,r,LL,RR,inc); sum[tr]=sum[ls]|sum[rs]; } inline ll query(int tr,int l,int r,int LL,int RR) { if(LL<=l&&r<=RR) return sum[tr]; spread(tr); R md=(l+r)>>1,ret=0; if(LL<=md) ret|=query(ls,l,md,LL,RR); if(RR>md) ret|=query(rs,md+1,r,LL,RR); return ret; } signed main() { n=g(),m=g(); for(R i=1;i<=n;++i) w[i]=g(); for(R i=2,u,v;i<=n;++i) u=g(),v=g(),add(u,v),add(v,u); dfs(1); build(1,1,n); for(R i=1;i<=m;++i) { R k=g(),u=g(),inc; if(k&1) inc=g(),update(1,1,n,dfn[u],dfn[u]+sz[u]-1,inc); else printf("%d\n",ppc(query(1,1,n,dfn[u],dfn[u]+sz[u]-1))); } }
2019.04.19