[BZOJ]1103: [POI2007]大都市meg

Description

在经济全球化浪潮的影响下,习惯于漫步在清晨的乡间小路的邮递员Blue Mary也开始骑着摩托车传递邮件了。不过,她经常回忆起以前在乡间漫步的情景。昔日,乡下有依次编号为1..n的n个小村庄,某些村庄之间有一些双向的土路。从每个村庄都恰好有一条路径到达村庄1(即比特堡)。并且,对于每个村庄,它到比特堡的路径恰好只经过编号比它的编号小的村庄。另外,对于所有道路而言,它们都不在除村庄以外的其他地点相遇。在这个未开化的地方,从来没有过高架桥和地下铁道。随着时间的推移,越来越多的土路被改造成了公路。至今,Blue Mary还清晰地记得最后一条土路被改造为公路的情景。现在,这里已经没有土路了——所有的路都成为了公路,而昔日的村庄已经变成了一个大都市。 Blue Mary想起了在改造期间她送信的经历。她从比特堡出发,需要去某个村庄,并且在两次送信经历的间隔期间,有某些土路被改造成了公路.现在Blue Mary需要你的帮助:计算出每次送信她需要走过的土路数目。(对于公路,她可以骑摩托车;而对于土路,她就只好推车了。)

Input


第一行是一个数n(1 < = n < = 2 50000). 
以下n-1行,每行两个整数a,b(1 < =  a以下一行包含一个整数m(1 < = m < = 2 50000),表示Blue Mary曾经在改造期间送过m次信。 
以下n+m-1行,每行有两种格式的若干信息,表示按时间先后发生过的n+m-1次事件: 
若这行为 A a b(a若这行为 W a, 则表示Blue Mary曾经从比特堡送信到村庄a。

Output

有m行,每行包含一个整数,表示对应的某次送信时经过的土路数目。

Sample Input

5
1 2
1 3
1 4
4 5
4
W 5
A 1 4
W 5
A 4 5
W 5
W 2
A 1 2
A 1 3

Sample Output

2
1
0
1


HINT



这是我做的第二道有关DFS序,BFS序的题了。这种题说难不难,说简单不简单,重在对于看出问题的本质,分析出究竟改变了什么,怎么改变了,改变量有什么特点。


这题抽象一下,最先每个点的值存的是到1的距离,也就是深度,然后给出m个操作,操作有两种:1.询问一个点的值;2.将一个点及他的子树的值全部减1。

我们发现,我们每次操作,是想尽量快的更改他和他的子树,那么自然他和他的子树放在一起更好改,于是可以想到DFS序,对于一棵树的DFS序,一个节点的儿子一定是在一个区间内的,那么只要我们记下这个区间在哪儿,每次就可以想怎么搞怎么搞了。


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <climits>
#include <cstring>
using namespace std;
#define MAX_N 300000
int n,m;
int tot;
int fir[MAX_N*2],en[MAX_N*2],nex[MAX_N*2];
void ins(int a,int b){
	nex[++tot]=fir[a];
	fir[a]=tot;
	en[tot]=b;
	
	nex[++tot]=fir[b];
	fir[b]=tot;
	en[tot]=a;
}
int top,sta[MAX_N*2];
int L[MAX_N],R[MAX_N],bel[MAX_N],dep[MAX_N];
void dfs(int now,int deep){
	sta[++top]=now;
	bel[now]=top;
	dep[now]=deep;
	L[now]=top+1;
	for (int k=fir[now];k;k=nex[k])
		if (!bel[en[k]])
			dfs(en[k],deep+1);
	R[now]=top;
	if (R[now]<L[now]) L[now]=R[now]=0;
}
int sum[MAX_N*4],tag[MAX_N*4];
void build(int k,int l,int r){
	if (l==r){
		sum[k]=dep[sta[l]];
		return;
		}
	int mid=(l+r)/2;
	build(k*2,l,mid);
	build(k*2+1,mid+1,r);
	sum[k]=sum[k*2]+sum[k*2+1];
}
void updata(int k){
	sum[k]=sum[k*2]+sum[k*2+1];
}
void down(int k,int l,int r){
	int mid=(l+r)/2;
	sum[k*2]+=(mid-l+1)*tag[k];
	sum[k*2+1]+=(r-(mid+1)+1)*tag[k];
	tag[k*2]+=tag[k];
	tag[k*2+1]+=tag[k];
	tag[k]=0;
	updata(k);
}
int query(int k,int l,int r,int x){
	if (l==r){
		return sum[k];
		}
	if (tag[k]) down(k,l,r);
	int mid=(l+r)/2,ans=0;
	if (x<=mid) return query(k*2,l,mid,x);
	if (mid+1<=x) return query(k*2+1,mid+1,r,x);
}
void modify(int k,int l,int r,int s,int t){
	if (s<=l&&r<=t){
		sum[k]-=(r-l+1);
		tag[k]--;
		return ;
		}
	if (tag[k]) down(k,l,r);
	int mid=(l+r)/2;
	if (s<=mid) modify(k*2,l,mid,s,t);
	if (mid+1<=t) modify(k*2+1,mid+1,r,s,t);
	updata(k);
}
int main(){
//	freopen("1103.in","r",stdin);
//	freopen("1103.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<n;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		ins(a,b);
		}
	dfs(1,0);
//	for (int i=1;i<=top;i++) printf("%d ",sta[i]);printf("\n");
//	for (int i=1;i<=n;i++) printf("%d %d\n",L[i],R[i]);
	build(1,1,top);
//	for (int i=1;i<=n;i++) printf("%d ",dep[i]);
	
	scanf("%d",&m);
	while(m){
		char ch;
		scanf("\n%c",&ch);
		if (ch=='W'){
			m--;
			int x;
			scanf("%d",&x);
			printf("%d\n",query(1,1,n,bel[x]));
			}
		if (ch=='A'){
			int x,y;
			scanf("%d%d",&x,&y);
			if (x>y) swap(x,y);
			modify(1,1,n,bel[y],bel[y]);
			if (!(L[y]==0||R[y]==0))modify(1,1,n,L[y],R[y]);
			}
		}
	
	
	return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值