【嵊中模拟2019.02.01】【BZOJ1103】大都市meg

题目链接

题解

设DFS序(栈操作序列)为$seq$,点$i$入栈位置为$u_{i}$,出栈位置为$v_{i}$。

发现以$i$为根的子树的所有点的出入栈位置都在$u_{i}$和$v_{i}$之间。

考虑设标记序列$mark$,令$\forall i\in [1,n], mark_{u_{i}}=1, mark_{v_{i}}=-1$,代表点$i$到父亲的这条边的影响,入栈时增加$1$,出站时增加$-1$

若点$i$到父亲的这条边从土路被改为公路,则要消去这条边的影响,即$mark_{u_{i}}-1, mark_{v_{i}}+1$。

用树状数组维护$mark$的前缀和序列,设为$sum$,则$sum_{i}$即为根到点$i$的路径上的边数,支持单点修改和区间查询。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
    int n;
struct E{
    int to,nxt;
}e[500003];
    int sum;
    int h[250003];
void adde(int from,int to){
    sum++;
    e[sum].to=to;
    e[sum].nxt=h[from];
    h[from]=sum;
}
    bool vis[250003];
    int seq[500003],cnt;
    int u[250003],v[250003];
void dfs(int x){
    seq[++cnt]=x;    u[x]=cnt;
    int y;
    for(int i=h[x];i;i=e[i].nxt){
        y=e[i].to;
        if(vis[y])
            continue;
        vis[y]=1;
        dfs(y);
    }
    seq[++cnt]=x;    v[x]=cnt;
}
    int t[500003];
int lowbit(int p){
    return p&(-p);
}
void add(int p,int n,int x){
    while(p<=n){
        t[p]+=x;
        p+=lowbit(p);
    }
}
int fpre(int p){
    int ans=0;
    while(p){
        ans+=t[p];
        p-=lowbit(p);
    }
    return ans;
}
    int m;
int max(int x,int y){
    if(x>y)
        return x;
    return y;
}
int main(){
    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);
    scanf("%d",&n);
    sum=0;
    memset(h,0,sizeof(h));
    int x,y;
    for(int i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        adde(x,y);    adde(y,x);
    }
    memset(vis,0,sizeof(vis));
    cnt=0;    vis[1]=1;
    dfs(1);
    memset(t,0,sizeof(t));
    for(int i=2;i<=n;i++){
        add(u[i],cnt,1);
        add(v[i],cnt,-1);
    }
    scanf("%d",&m);    getchar();
    char typ;
    int dlvcnt=0;
    for(;1;){
        typ=getchar();    getchar();
        scanf("%d",&x);    getchar();
        if(typ=='A'){
            scanf("%d",&y);    getchar();
            x=max(x,y);                
            add(u[x],cnt,-1);
            add(v[x],cnt,+1);
        }
        else {
            printf("%d\n",fpre(u[x]));
            dlvcnt++;
            if(dlvcnt==m)
                break;
        }
    }
    return 0;
}

 

posted @ 2019-02-13 13:06  汉谡  阅读(164)  评论(0编辑  收藏  举报