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)/~