[CodeForces620E] New Year Tree

原题网址:http://codeforces.com/problemset/problem/620/E

啊,从这篇博客开始我就不复制题目了,毕竟大家点进来都是为了我的AC代码。

好的,这道题的题目大意就是,有一棵树,给它染色,刚开始的颜色是给定的,然后有两个操作:

1,输入v,x,将v和其所有子节点染色成x;

2,输入x,输出x的所有子节点的染色种类;

很显然,这个输入和输出的方式很有区间的味道(行家啊~

于是,我们考虑到dfs序,可以把一棵树降维到一维;

然后,我就写了一个朴素的欧拉序(节点进出的时候记录进dfs_num数组)

然后,,,我要怎么数颜色???

瞄了一眼数据范围,最多60种颜色,这明白着提醒我:放心吧,随便开数组,不会mle的~

//在教练的提醒下我选择了状压

把每种颜色作为二进制下的一位,比如(1000)2就表示这个节点有3号颜色;

区间合并的时候,就按位或一下,比如表示颜色三的(1000)和表示颜色二的(100)按位或后就是(1100)表示既有三又有二;

如果有多种颜色的时候,这种方法可以起到有效的去重(这让本打算开60个数组的我情何以堪

于是代码就出来了

漂亮得TLE了。。。

 

然后优化就是把欧拉序改成了前序遍历,就AC了

下面放AC代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define maxn 400005
using namespace std;
inline void read(int &x)
{
	x=0;int f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	x*f;
}
inline void read(long long &x)
{
	x=0;int f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	x*f;
}
int N,M;
long long color_v[maxn];
long long bas=1;
struct node{
	int nex,to;
}edge[maxn<<2];
int head[maxn],tot;
inline void insert(int from,int to)
{
	tot++;
	edge[tot].nex=head[from];
	head[from]=tot;
	edge[tot].to=to;
}
long long st[maxn],ed[maxn],dfs_num[maxn],t;
void dfs(int x,int u)
{
	//cout<<"dfs note: "<<x<<" "<<t<<endl;
	//cout<<x<<" ";
	st[x]=++t;
	dfs_num[t]=color_v[x];
	for(int i=head[x];i;i=edge[i].nex)
	{
		if(edge[i].to!=u)
		{
			dfs(edge[i].to,x);
		}
	}
	ed[x]=t;
	//cout<<x<<" ";
}
struct tree{
	int l,r;
	long long color;
}tree[maxn<<4];
int bit(long long i)
{
	int ans=0;
	while(i)
	{
		ans+=i&1;
		i>>=1;
	}
	return ans;
}
void push_up(int rt)
{
	tree[rt].color=tree[rt<<1].color|tree[rt<<1|1].color;
}
void push_down(int rt)
{
	tree[rt<<1].color=tree[rt].color;
	tree[rt<<1|1].color=tree[rt].color;
}
void build(int rt,int l,int r)
{
	tree[rt].l=l;
	tree[rt].r=r;
	if(l==r)
	{
		tree[rt].color=bas<<dfs_num[l];
		return ;
	}
	int mid=l+r>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
	push_up(rt);
}
void update(int rt,int l,int r,int col)
{
	if(tree[rt].l>r||tree[rt].r<l)
		return ;
	if(tree[rt].l>=l&&tree[rt].r<=r)
	{
		tree[rt].color=bas<<col;
		return ;
	}
	if(bit(tree[rt].color)==1)
		push_down(rt);
	int mid=tree[rt].l+tree[rt].r>>1;
	if(l<=mid)
		update(rt<<1,l,r,col);
	if(r>mid)
		update(rt<<1|1,l,r,col);
	push_up(rt);
}
long long query(int rt,int l,int r)
{
	if(tree[rt].l>r||tree[rt].r<l)
		return 0;
	if(tree[rt].l>=l&&tree[rt].r<=r)
	{
		return tree[rt].color;
	}	
	if(tree[rt].l==tree[rt].r)
		return 0;
	if(bit(tree[rt].color)==1)
		push_down(rt);
	int mid=tree[rt].l+tree[rt].r>>1;
	long long ans=0;
	if(l<=mid)
	{
		ans|=query(rt<<1,l,r);
	}
	/*if(ans==(1<<23))
		cout<<"LEFT ERROR:  "<<tree[rt].l<<" "<<tree[rt].r<<endl;*/	
	if(r>mid)
	{
		ans|=query(rt<<1|1,l,r);
	}	
	return ans;
}
/*void search(long long rt)
{
	if(bit(tree[rt].color)==1)
	{
		for(long long i=tree[rt].l;i<=tree[rt].r;i++)
			cout<<log2(tree[rt].color)<<" ";
		return ;
	}
	search(rt<<1);
	search(rt<<1|1);
}*/
int main()
{
	read(N);read(M);
	for(int i=1;i<=N;i++)
	{
		read(color_v[i]);
	}
	int u;
	int v;
	for(int i=1;i<N;i++)
	{
		read(u);read(v);
		insert(u,v);
		insert(v,u);
	}
	//cout<<"dfs note: ";
	dfs(1,1);
	//cout<<endl;
	build(1,1,t);
	int op;
	for(int i=1;i<=M;i++)
	{
		//cout<<"lin note: ";
		//search(1);
		//cout<<endl;
		read(op);
		if(op==1)
		{
			read(u);read(v);
			update(1,st[u],ed[u],v);
		}
		else
		{
			read(u);
			//cout<<"check :"<<st[u]<<" "<<ed[u]<<endl;
			printf("%d\n",bit(query(1,st[u],ed[u])));
		}
	}
}
/*
10 10
23 25 23 42 23 53 49 40 28 44
1 7
1 2
2 4
4 10
8 10
6 8
3 8
5 3
9 5
2 10
1 6 52
1 8 43
2 3

*/

 

转载于:https://www.cnblogs.com/sherrlock/p/9525783.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值