【线段树】【HELP】美丽的中国结 rqnoj60

题目:美丽的中国结 rqnoj60


【题目背景】
kitty刚刚高三毕业.看到同学们都回家的回家,旅游的旅游,她的心里有些落寞.英俊潇洒风流倜傥迷倒万千KL却仅对kitty感冒的fish看在眼里,急在心里.一天,fish提出和kitty两个人一起外出旅游.kitty犹豫了几天,想好能瞒过家长的理由后(要问是什么……自己猜去),答应了.fish很高兴地带着kitty去登记了(别想歪,登记旅游团而已……),日照青岛五日游.
当然啦,他们玩得很高兴.虽然这次旅行是fish先提议的,但kitty因为玩得很畅快(刚高考完嘛),所以想送给fish一份礼物,一份能让见多识广的fish都无法忘怀的礼物.她从路边 9¾站台的某算命先生那里得知中国结具有增加RP的效果,而这正是fish所需要的,因此她决定动手给fish编一个奇特的中国结.


【题目描述】
中国结形式多样,fish会喜欢什么样的呢?思考几天后,kitty决定给fish编一个树状的中国结.这个中国结有n个结点(编号1,2,…,n),这n个结点之间总共恰有n-1条线相连,其中结点1上是树的根.这是一个奇特的中国结,因此它的编织方式也很奇特.在编织过程中的每一步骤,kitty有时需要将一个结点子树里的所有结点i的状态全部取反(如果原来结点i已经打结,则解开i,否则将结点i打结),有时又需要知道一个结点的子树里有多少已经打结的结点,你能帮助可爱的kitty完成这份礼物吗?


【数据规模】
对于40% 的数据,1≤n≤10000, 1≤m≤20000
对于100%的数据,1≤n≤100000, 1≤m≤100000
输入格式


【输入】
第一行有个整数n,表示这个中国结有n个结点
以下n-1行,每行有两个整数u和v(1≤u,v≤n),表示结点u和v间有一条线相连;
再一行有个整数m,表示kitty要进行的步骤数
以下m行,每行可能为:
"C x":表示将结点x的子树中所有结点的状态取反(包括x)

"Q x":表示kitty想知道结点x的子树中有多少已经打结的结点(包括x)


【输出】
对于每个“Q x”输出一行整数,表示结点x的子树中有多少已经打结的结点(包括x)


【样例输入】
5
1 2
1 3
2 4
2 5
5
Q 1
C 1
Q 1
C 2
Q 1


【样例输出】
0
5

2








很纠结的一道题。。。。。

线段树,但是题目没有给出区间,不过很明显的一眼可以看出来是线段树

怎么建立线段树呢?DFS!

从1开始DFS,然后用一个类似强连通里面的时间戳来建立一个区间


区间建立起来了,剩下的就好说了,用val[]来记录当前区间是否为1,或0(如果0和1都有则标记为-1)

很交了好多次,都超时了,刚开始以为是链表指针动态分配空间的问题,不过改成伪链表也超时了

后来东改西改,多用了一个sum来维护当前区间里有几个1,希望查询的时候能快点,结果还是超时了

纠结了好久。。。。。。


当时的C++ Code

#include<cstdio>
const int N=100000+10;
#define data_up() if(val[p]==-1&&val[p<<1]==val[(p<<1)+1])val[p]=val[p<<1]
int n,m;
struct link{int y;link *next;}*head[N];
int L[N],R[N],tt=0;
bool hash[N];
int val[N*4];

void inlink(int x,int y)
{
	link *node=new link;
	node->y=y;
	node->next=head[x];
	head[x]=node;
}

void read()
{
	//freopen("chinese.in","r",stdin);
	//freopen("chinese.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		inlink(u,v);
		inlink(v,u);
	}
}

void dfs(int x)
{
	if(hash[x]) return;	hash[x]=true;
	tt++;L[x]=tt;
	for(link *node=head[x];node;node=node->next) dfs(node->y);
	R[x]=tt;
}

void data_down(int p)
{
	if(val[p]!=-1)
	{
		val[p<<1]=val[(p<<1)+1]=val[p];
		val[p]=-1;
	}
}

void change(int p,int l,int r,int a,int b)
{
	if(a<=l && b>=r)
	{
		if(val[p]!=-1)
		{
			val[p]=1-val[p];
			return;
		}
	}
	int m=(l+r)>>1;
	data_down(p);
	if(a<=m) change(p<<1,l,m,a,b);
	if(b>m) change((p<<1)+1,m+1,r,a,b);
	data_up();
}

int query(int p,int l,int r,int a,int b)
{
	if(a<=l&&b>=r)
	{
		if(val[p]==1) return r-l+1;
		if(val[p]==0) return 0;
	}
	int m=(l+r)>>1,x1=0,x2=0;
	data_down(p);
	if(a<=m) x1=query(p<<1,l,m,a,b);
	if(b>m) x2=query((p<<1)+1,m+1,r,a,b);
	data_up();
	return x1+x2;
}

void work()
{
	dfs(1);
	//for(int i=1;i<=n;i++) printf("%d ",L[i]);puts("");
	//for(int i=1;i<=n;i++) printf("%d ",R[i]);puts("");
	scanf("%d",&m);
	while(m--)
	{
		char op;int x;
		scanf("\n%c%d",&op,&x);
		if(op=='C') change(1,1,tt,L[x],R[x]);
		else printf("%d\n",query(1,1,tt,L[x],R[x]));
	}
}

int main()
{
	read();
	work();
	//while(1);
	return 0;
}



后来分析有原因(应该是查询的时候慢了。。。。)

不过改了一下,成绩还是和上面一样(超时6组)

/*http://blog.csdn.net/jiangzh7
By Jiangzh*/
#include<cstdio>
const int N=100000+10;
#define data_up() if(val[p]==-1&&val[p<<1]==val[(p<<1)+1])val[p]=val[p<<1]
int n,q;
struct link{int y;link *next;}*head[N];
int L[N],R[N],tt=0;
bool hash[N];
int val[N*4];
int sum[N*4];

void inlink(int x,int y)
{
	link *node=new link;
	node->y=y;
	node->next=head[x];
	head[x]=node;
}

void read()
{
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		inlink(u,v);
		inlink(v,u);
	}
}

void dfs(int x)
{
	if(hash[x]) return;	hash[x]=true;
	tt++;L[x]=tt;
	for(link *node=head[x];node;node=node->next) dfs(node->y);
	R[x]=tt;
}

void data_down(int p)
{
	if(val[p]!=-1)
	{
		val[p<<1]=val[(p<<1)+1]=val[p];
		val[p]=-1;
	}
}

void change(int p,int l,int r,int a,int b)
{
	if(a<=l && b>=r)
	{
		if(val[p]!=-1)
		{
			if(val[p]==0)
			{
				val[p]=1;
				sum[p]=r-l+1;
			}
			else if(val[p]==1)
			{
				val[p]=0;
				sum[p]=0;
			}
			return;
		}
	}
	int m=(l+r)>>1;
	if(val[p]==1) {sum[p<<1]=m-l+1;sum[(p<<1)+1]=r-(m+1)+1;}
	if(val[p]==0) {sum[p]=sum[p<<1]=sum[(p<<1)+1]=0;}
	data_down(p);
	if(a<=m) change(p<<1,l,m,a,b);
	if(b>m) change((p<<1)+1,m+1,r,a,b);
	data_up();
	sum[p]=sum[p<<1]+sum[(p<<1)+1];
}

int query(int p,int l,int r,int a,int b)
{
	if(a<=l&&b>=r)
	{
		//if(val[p]==1) return r-l+1;
		//if(val[p]==0) return 0;
		return sum[p];
	}
	int m=(l+r)>>1,x1=0,x2=0;
	if(val[p]==1) {sum[p<<1]=m-l+1;sum[(p<<1)+1]=r-(m+1)+1;}
	if(val[p]==0) {sum[p]=sum[p<<1]=sum[(p<<1)+1]=0;}
	data_down(p);
	if(a<=m) x1=query(p<<1,l,m,a,b);
	if(b>m) x2=query((p<<1)+1,m+1,r,a,b);
	data_up();
	sum[p]=sum[p<<1]+sum[(p<<1)+1];
	return x1+x2;
}

void work()
{
	dfs(1);
	//for(int i=1;i<=n;i++) printf("%d ",L[i]);puts("");
	//for(int i=1;i<=n;i++) printf("%d ",R[i]);puts("");puts("");puts("");
	scanf("%d",&q);
	for(int i=1;i<=q;i++)
	{
		char op;int x;
		scanf("\n%c%d",&op,&x);
		if(op=='C') change(1,1,tt,L[x],R[x]);
		else printf("%d\n",query(1,1,tt,L[x],R[x]));
		//for(int i=1;i<=10;i++) printf("%d ",val[i]);puts("");
		//for(int i=1;i<=10;i++) printf("%d ",sum[i]);puts("");puts("");
	}
}

int main()
{
	freopen("chinese.in","r",stdin);
	freopen("chinese.out","w",stdout);
	read();
	work();
	//while(1);
	return 0;
}


如果大家看到了我的代码,想出来是怎么回事的,请帮我改一下,感激不尽~~




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值