[BZOJ1103] [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

题目分析

树链剖板子题 路径边权+ 路径查询

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
int n,m;
int head[250100],net[500100],to[500100],val[250100],value[250100],size[250100],fa[250100],deep[250100];
int number[250100],son[250100],top[250100];
int tot,cnt;
struct your
{
    int x,y,sum;
    int add;
}a[500100*2];
void add(int x,int y)
{
    net[++tot]=head[x];
    head[x]=tot;
    to[tot]=y;
}
void dfs(int x)
{
    deep[x]=deep[fa[x]]+1;
    size[x]=1;
    for(int i=head[x];i;i=net[i])
        if(to[i]!=fa[x])
        {
            fa[to[i]]=x;
            dfs(to[i]);
            val[to[i]]=1;
            size[x]+=size[to[i]];
            if(size[to[i]]>size[son[x]]) son[x]=to[i];
        }
}
void dfs2(int x,int temp)
{
    number[x]=++cnt;
    top[x]=temp;
    value[cnt]=val[x];
    if(son[x]) dfs2(son[x],temp);
    for(int i=head[x];i;i=net[i])
        if(to[i]!=son[x]&&to[i]!=fa[x])
            dfs2(to[i],to[i]);
}
void pushdown(int num)
{
    a[num<<1].add=a[num<<1|1].add=1;
    a[num<<1].sum=a[num<<1|1].sum=0;
    a[num].add=0;
}
void build(int dx,int dy,int num)
{
    a[num].x=dx,a[num].y=dy;
    if(dx==dy) 
    {
        a[num].sum=value[dx];
        return ;
    }
    int mid=(dx+dy)>>1;
    build(dx,mid,num<<1),build(mid+1,dy,num<<1|1);
    a[num].sum=a[num<<1].sum+a[num<<1|1].sum;
    return ;
}
void update(int dx,int dy,int num)
{
    if(a[num].x==dx&&a[num].y==dy) 
    {
        a[num].add=1,a[num].sum=0;
        return ;
    }
    if(a[num].add) pushdown(num);
    int mid=(a[num].x+a[num].y)>>1;
    if(dx>mid) update(dx,dy,num<<1|1);
    else if(dy<=mid) update(dx,dy,num<<1);
    else update(dx,mid,num<<1),update(mid+1,dy,num<<1|1);
    a[num].sum=a[num<<1].sum+a[num<<1|1].sum;
}
int ask(int dx,int dy,int num)
{
    if(a[num].x==dx&&a[num].y==dy)
        return a[num].sum;
    if(a[num].add) pushdown(num);
    int mid=(a[num].x+a[num].y)>>1;
    if(dx>mid) return ask(dx,dy,num<<1|1);
    if(dy<=mid) return ask(dx,dy,num<<1);
    return ask(dx,mid,num<<1)+ask(mid+1,dy,num<<1|1);
}
void change(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        update(number[top[x]],number[x],1);
        x=fa[top[x]];
    }
    if(deep[x]>deep[y]) swap(x,y);
    if(x==y) return ;
    update(number[x]+1,number[y],1);
}
int find(int x,int y)
{
    int sum=0;
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        sum+=ask(number[top[x]],number[x],1);
        x=fa[top[x]];
    }
    if(deep[x]>deep[y]) swap(x,y);
    if(x==y) return sum;
    return sum+ask(number[x]+1,number[y],1);
}
char s[10];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y),add(y,x);
    }
    dfs(1),dfs2(1,1);
    build(1,n,1);
    scanf("%d",&m);
    for(int i=1;i<=n+m-1;i++)
    {
        int x,y;
        scanf("%s",&s[0]);
        if(s[0]=='A') 
        {
            scanf("%d%d",&x,&y);
            change(x,y);
        }
        else
        {
            scanf("%d",&x);
            printf("%d\n",find(1,x));
        }
    }
} 

发表评论

邮箱地址不会被公开。 必填项已用*标注