1103: [POI2007]大都市meg(dfs序+线段树||树状数组)

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
在这里插入图片描述
挺折磨人的一道题。。
首先得看懂题意,然后转换题意。两种操作:一种是求指定点的权值。另一种是更新一个区间。
将a-b的路径改为公路可以视为将a-b的路径的权值改为0,则题目转为经一系列边权的修改后询问根节点与一个节点的距离。刷一遍DFS序,比如样例中树的dfs序为1223345541。将进入的权值赋为1,离开的权值赋为-1,起点的进出权值都为0(进出权值记录在中间一行)。
得:
1 2 2 3 3 4 5 5 4 1
0 1 -1 1 -1 1 1 -1 -1 0
0 1 0 1 0 1 2 1 0 0
然后有什么用?我们可以发现起点到任意点N的距离都为N的进入点的前缀和(最下面一行)。
再试试修改,将1-4的权值改为0,只需将深度较深的点的进入权值改为0,离开的权值也改为0就好了。
1 2 2 3 3 4 5 5 4 1
0 1 -1 1 -1 0 1 -1 0 0
0 1 0 1 0 0 1 0 0 0
第二种操作直接修改深度大的点就好,这怎么也没想到。直接线段树或者树状数组修改就行。
①:线段树+dfs序

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define ll long long
using namespace std;

const int maxx=250500;
int head[maxx],pre[maxx],s[maxx],t[maxx];
int dep[maxx],fa[maxx];
struct edge{
	int next;
	int to;
}e[maxx*2];
struct node{
	int l;
	int r;
	int v;
	int lazy;
}p[maxx*4];
int n,m,tot,sign;
/*-----------------事前准备----------------*/ 
void init()
{
	tot=sign=0;
	memset(head,-1,sizeof(head));
	memset(dep,-1,sizeof(dep));
}
void add(int u,int v)
{
	e[tot].to=v,e[tot].next=head[u],head[u]=tot++;
}
/*--------------------dfs序-------------------*/ 
void dfs(int u,int f)
{
	dep[u]=dep[f]+1;
	s[u]=++sign;
	pre[sign]=u;
	fa[u]=f;
	for(int i=head[u];i!=-1;i=e[i].next)
	{
		int to=e[i].to;
		if(to==f) continue;
		dfs(to,u);
	}
	t[u]=sign;
}
/*-------------------线段树-------------------*/
void pushup(int cur)
{
	p[cur].v=p[2*cur].v+p[2*cur+1].v;
}
void pushdown(int cur)
{
	if(p[cur].lazy)
	{
		p[2*cur].lazy+=p[cur].lazy;
		p[2*cur+1].lazy+=p[cur].lazy;
		p[2*cur].v+=p[cur].lazy;
		p[2*cur+1].v+=p[cur].lazy;
		p[cur].lazy=0;
	}
}
void build(int l,int r,int cur)
{
	p[cur].l=l;
	p[cur].r=r;
	p[cur].v=p[cur].lazy=0;
	if(l==r)
	{
		p[cur].v=dep[pre[l]];
		return ;
	}
	int mid=(l+r)/2;
	build(l,mid,2*cur);
	build(mid+1,r,2*cur+1);
	pushup(cur);
}
void update(int l,int r,int cur,int v)
{
	int L=p[cur].l;
	int R=p[cur].r;
	if(l<=L&&R<=r)
	{
		p[cur].lazy+=v;
		p[cur].v+=v;
		return ;
	}
	pushdown(cur);
	int mid=(L+R)/2;
	if(r<=mid) update(l,r,2*cur,v);
	else if(l>mid) update(l,r,2*cur+1,v);
	else
	{
		update(l,mid,2*cur,v);
		update(mid+1,r,2*cur+1,v);
	}
	pushup(cur);
}
int query(int cur,int x)
{
	int L=p[cur].l;
	int R=p[cur].r;
	if(L==R)
	{
		return p[cur].v;
	}
	pushdown(cur);
	int mid=(L+R)/2;
	if(x<=mid) return query(2*cur,x);
	else if(mid<x) return query(2*cur+1,x);
}
int main()
{
	init();
	scanf("%d",&n);
	int x,y;
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	dfs(1,0);
	build(1,n,1);
	scanf("%d",&m);
	char xx[2];
	for(int i=1;i<=n+m-1;i++)
	{
		scanf("%s",xx);
		if(xx[0]=='W')
		{
			scanf("%d",&x);
			printf("%d\n",query(1,s[x]));
		}
		else if(xx[0]=='A')
		{
			scanf("%d%d",&x,&y);
			x=max(x,y);
			update(s[x],t[x],1,-1);
		}
	}
	return 0;
}

在这里插入图片描述
②:树状数组+dfs序

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
#define ll long long
using namespace std;

const int maxx=250500;
int head[maxx],pre[maxx],dep[maxx],s[maxx],t[maxx];
int sum[maxx];
struct edge{
	int to;
	int next;
}e[maxx*4];
int n,m,tot,sign;
int lowbit(int x){return x&-x;}
void init()
{
	tot=sign=0;
	memset(head,-1,sizeof(head));
	memset(dep,-1,sizeof(dep));
	memset(pre,0,sizeof(pre));
}
void add(int u,int v)
{
	e[tot].to=v,e[tot].next=head[u],head[u]=tot++; 
}
void dfs(int u,int f)
{
	dep[u]=dep[f]+1;
	s[u]=++sign;
	pre[sign]=u;
	for(int i=head[u];i!=-1;i=e[i].next)
	{
		int to=e[i].to;
		if(to==f) continue;
		dfs(to,u);
	}
	t[u]=sign;
}
void update(int cur,int add)
{
	while(cur<=maxx*2)
	{
		sum[cur]+=add;
		cur+=lowbit(cur);
	}
}
int query(int cur)
{
	int ans=0;
	while(cur>0)
	{
		ans+=sum[cur];
		cur-=lowbit(cur);
	}
	return ans;
}
int main()
{
	init();
	scanf("%d",&n);
	int x,y;
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	dfs(1,0);
	for(int i=2;i<=n;i++)
	{
		update(s[i],1);
		update(t[i]+1,-1);
	}
	scanf("%d",&m);
	char xx[2];
	for(int i=1;i<=n+m-1;i++)
	{
		scanf("%s",xx);
		if(xx[0]=='W')
		{
			scanf("%d",&x);
			printf("%d\n",query(s[x]));
		}
		else if(xx[0]=='A')
		{
			scanf("%d%d",&x,&y);
			update(max(s[x],s[y]),-1);
			update(min(t[x],t[y])+1,1);
		}
	}
	return 0;
}

在这里插入图片描述
线段树再一次被虐。。
明天就回学校打多校了,希望是一个积极的暑假,别虚度了!
努力加油a啊,(o)/~

### 解决PyCharm无法加载Conda虚拟环境的方法 #### 配置设置 为了使 PyCharm 能够成功识别并使用 Conda 创建的虚拟环境,需确保 Anaconda 的路径已正确添加至系统的环境变量中[^1]。这一步骤至关重要,因为只有当 Python 解释器及其关联工具被加入 PATH 后,IDE 才能顺利找到它们。 对于 Windows 用户而言,在安装 Anaconda 时,默认情况下会询问是否将它添加到系统路径里;如果当时选择了否,则现在应该手动完成此操作。具体做法是在“高级系统设置”的“环境变量”选项内编辑 `Path` 变量,追加 Anaconda 安装目录下的 Scripts 文件夹位置。 另外,建议每次新建项目前都通过命令行先激活目标 conda env: ```bash conda activate myenvname ``` 接着再启动 IDE 进入工作区,这样有助于减少兼容性方面的问题发生概率。 #### 常见错误及修复方法 ##### 错误一:未发现任何解释器 症状表现为打开 PyCharm 新建工程向导页面找不到由 Conda 构建出来的 interpreter 列表项。此时应前往 Preferences/Settings -> Project:...->Python Interpreter 下方点击齿轮图标选择 Add...按钮来指定自定义的位置。按照提示浏览定位到对应版本 python.exe 的绝对地址即可解决问题。 ##### 错误二:权限不足导致 DLL 加载失败 有时即使指定了正确的解释器路径,仍可能遇到由于缺乏适当的操作系统级许可而引发的功能缺失现象。特别是涉及到调用某些特定类型的动态链接库 (Dynamic Link Library, .dll) 时尤为明显。因此拥有管理员身份执行相关动作显得尤为重要——无论是从终端还是图形界面触发创建新 venv 流程均如此处理能够有效规避此类隐患。 ##### 错误三:网络连接异常引起依赖下载超时 部分开发者反馈过因网速慢或者其他因素造成 pip install 操作中途断开进而影响整个项目的初始化进度条卡住的情况。对此可尝试调整镜像源加速获取速度或是离线模式预先准备好所需资源包后再继续后续步骤。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starlet_kiss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值