回去再调.
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=4e5+5; ll col[N]; vector<int>g[N]; int now[N],last[N],id=0,sz[N];//这个数组之前是x的现在节点id是谁.现在是id,对应之前x是多少. struct seg{ ll l,r,sum,lazy; }tr[N<<2]; void dfs(int u,int fa) { now[u]=++id;last[id]=u; sz[u]=1; for(int x:g[u]) { if(x==fa) continue; dfs(x,u);sz[u]+=sz[x]; } } void pushup(int u) { tr[u].sum=tr[u<<1].sum|tr[u<<1|1].sum; } void pushdown(int u) { if(tr[u].lazy) { tr[u<<1|1].lazy=tr[u<<1].lazy=tr[u].lazy;tr[u].lazy=0; tr[u<<1].sum=tr[u<<1|1].sum=(1ll<<(tr[u].lazy-1)); } } void build(int u,int l,int r)//我拿1~n建树. { tr[u].l=l,tr[u].r=r; if(l==r) { tr[u].sum=(1ll<<col[last[l]]); return ; }int mid=(l+r)>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); pushup(u); } void modify(int u,int l,int r,int val)//实行操作1. { int L=tr[u].l,R=tr[u].r; if(r<L||l>R) return; pushdown(u); if(l<=L&&r>=R) { tr[u].lazy=val; tr[u].sum=(1ll<<(val-1)); } modify(u<<1,l,r,val); modify(u<<1|1,l,r,val); pushup(u); } int query(int u,int l,int r)//询问[l,r]区间的或值. { int L=tr[u].l,R=tr[u].r; if(r<L||l>R) return 0; pushdown(u); if(l<=L&&r>=R) { return tr[u].sum; }return query(u<<1,l,r)+query(u<<1|1,l,r); } int ans(ll u)//统计下二进制下有多少个1~ { int res=0; for(ll i=0;i<=60;i++) { if(u>>i&1) res++; }return res; } int main() { //输入! int n,m;scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&col[i]); for(int i=1;i<n;i++) { int u,v;scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); } //树链剖分! dfs(1,1); build(1,1,n); //询问! while(m--) { int op;scanf("%d",&op); if(op==1) { int x,y;scanf("%d%d",&x,&y); //改变x子树颜色全部改成y. modify(1,now[x],now[x]+sz[x]-1,y); } else { int x;scanf("%d",&x); //询问x点子树有多少不同的颜色. printf("%d\n",ans(query(1,now[x],now[x]+sz[x]-1))); } } return 0; }
(⊙o⊙)…改好了,细节错了忆点而已~
具体思路视频都讲了~
ac代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=4e5+5; ll col[N]; vector<int>g[N]; int now[N],last[N],id=0,sz[N];//这个数组之前是x的现在节点id是谁.现在是id,对应之前x是多少. struct seg{ ll l,r,sum,lazy; }tr[N<<3]; void dfs(int u,int fa) { now[u]=++id;last[id]=u; sz[u]=1; for(int x:g[u]) { if(x==fa) continue; dfs(x,u);sz[u]+=sz[x]; } } void pushup(int u) { tr[u].sum=tr[u<<1].sum|tr[u<<1|1].sum; } void pushdown(int u) { if(tr[u].lazy) { tr[u<<1|1].lazy=tr[u<<1].lazy=tr[u].lazy; tr[u<<1].sum=tr[u<<1|1].sum=(1ll<<(tr[u].lazy-1)); tr[u].lazy=0; } } void build(int u,int l,int r)//我拿1~n建树. { tr[u].l=l,tr[u].r=r; if(l==r) { tr[u].sum=(1ll<<(col[last[l]]-1)); return ; }int mid=(l+r)>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); pushup(u); } void modify(int u,int l,int r,int val)//实行操作1. { int L=tr[u].l,R=tr[u].r; if(r<L||l>R) return; pushdown(u); if(l<=L&&r>=R) { tr[u].lazy=val; tr[u].sum=(1ll<<(val-1)); return; } modify(u<<1,l,r,val); modify(u<<1|1,l,r,val); pushup(u); } ll query(int u,int l,int r)//询问[l,r]区间的或值. { int L=tr[u].l,R=tr[u].r; if(r<L||l>R) return 0; pushdown(u); if(l<=L&&r>=R) { return tr[u].sum; }return query(u<<1,l,r)|query(u<<1|1,l,r); } int ans(ll u)//统计下二进制下有多少个1~ { int res=0; for(ll i=0;i<=60;i++) { if(u>>i&1) res++; }return res; } int main() { //输入! int n,m;scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&col[i]); for(int i=1;i<n;i++) { int u,v;scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); } //树链剖分! dfs(1,1); build(1,1,n); //询问! while(m--) { int op;scanf("%d",&op); if(op==1) { int x,y;scanf("%d%d",&x,&y); //改变x子树颜色全部改成y. modify(1,now[x],now[x]+sz[x]-1,y); } else { int x;scanf("%d",&x); //询问x点子树有多少不同的颜色. printf("%d\n",ans(query(1,now[x],now[x]+sz[x]-1))); } } return 0; }