New Year Tree(dfs序+線段樹+二進位制)
阿新 • • 發佈:2021-01-16
技術標籤:codeforcesdfs序
題意: 給出一棵 n個節點的樹,根節點為 1。每個節點上有一種顏色 ci。m次操作。操作有兩種:
1 u c:將以 u為根的子樹上的所有節點的顏色改為c。
2 u:詢問以 u為根的子樹上的所有節點的顏色數量。
題解:
一看題目好像是個dfs序+線段樹的板子題,但是需要思考的是,怎麼查詢一段區間的顏色數目呢?
如果把這個問題解決了的話,這個題目也就相應的解決了。
看到顏色數目好像並不多,嗷,極好,60(2^60)正好在ll的範圍內。
我們可以考慮每一位儲存一種顏色,返回值為這段區間的**(或)|**。
這樣子dfs序建線段樹跑一邊即可。
/*Keep on going Never give up*/
//#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int maxn=3e6+10;
vector<int> edge[maxn];
int tree[maxn],add[maxn];
int a[maxn],in[maxn],out[maxn],id[maxn];
int cnt;
void dfs(int u,int fa){
in[u]=++cnt;
id[cnt]=u;
for(auto i:edge[u]){
if(i==fa) continue;
dfs(i,u);
}
out[u]=cnt;
}
void build(int node,int start,int ends){
if(start==ends){
tree[node]=1ll<<(a[id[start]]);
//cout<<"tree: "<<a[id[start]]<<" "<<tree[node]<<endl;
return ;
}
int mid=(start+ends)/2;
build(node*2,start,mid);
build(node*2+1,mid+1,ends);
tree[node]=tree[node*2]|tree[node*2+1];
}
void Add(int node,int val){
//cout<<"val"<<val<<endl;
add[node]=val;
tree[node]=1ll<<val;
//cout<<"addnode "<<tree[node]<<endl;
return ;
}
void push_down(int node){
if(add[node]==0) return ;
Add(node*2,add[node]);
Add(node*2+1,add[node]);
add[node]=0;
}
void update(int node,int start,int ends,int l,int r,int val){
if(start>=l&&ends<=r) return Add(node,val);
int mid=(start+ends)/2;
push_down(node);
if(l<=mid) update(node*2,start,mid,l,r,val);
if(mid<r) update(node*2+1,mid+1,ends,l,r,val);
tree[node]=tree[node*2]|tree[node*2+1];
}
int query(int node,int start,int ends,int l,int r){
if(start>=l&&ends<=r){
//cout<<"tree[node]"<<l<<tree[node]<<endl;
return tree[node];
}
int mid=(start+ends)/2;
push_down(node);
int ans=0;
if(l<=mid) ans|=query(node*2,start,mid,l,r);
if(mid<r) ans|=query(node*2+1,mid+1,ends,l,r);
return ans;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=0;i<n-1;i++){
int x,y;
cin>>x>>y;
edge[x].push_back(y);
edge[y].push_back(x);
}
dfs(1,-1);
//cout<<"okok"<<endl;
build(1,1,n);
//cout<<"okok"<<endl;
for(int i=0;i<m;i++){
int opt;
cin>>opt;
if(opt==1){
int x,y;
cin>>x>>y;
//cout<<in[x]<<" "<<out[x]<<endl;
update(1,1,n,in[x],out[x],y);
}
else{
int x;
cin>>x;
//cout<<"in:"<<in[x]<<" out:"<<out[x]<<endl;
int xxx=query(1,1,n,in[x],out[x]);
int ans=0;
//cout<<"xxx="<<xxx<<endl;
for(int i=0;i<=60;i++){
if(1&(xxx>>i)){
ans++;
//cout<<i<<" ";
}
}
//cout<<endl;
cout<<ans<<endl;
}
}
return 0;
}