1. 程式人生 > >PID 60 線段樹樹形轉線性

PID 60 線段樹樹形轉線性

題意:有一棵樹,開始的時候樹上的每一個節點都沒有打結,實現兩個操作 給樹上的某一個節點及其所有子節點翻轉

即每個打結的節點變成沒有節,沒打結的打結,然後詢問打結的節點的個數在某一棵子樹中的個數

解法:利用線段樹將節點轉化為線性結構,然後對重新標號的線段進行操作即可 

#include<cstdio>
#include<vector>
#include<iostream>
using namespace std;
#define maxn 111111
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
int ll[maxn],rr[maxn],cnt;
int rev[maxn<<2],sum[maxn<<2];
vector<int>g[maxn];
void up(int rt){sum[rt]=sum[ls]+sum[rs];}
void build(int rt,int l,int r){
    rev[rt]=0,sum[rt]=0;
    if(l==r)return ;
    build(ls,l,mid);
    build(rs,mid+1,r);
}
void down(int rt,int l,int r){
    if(rev[rt]){
        sum[ls]=(mid-l+1)-sum[ls];
        sum[rs]=(r-(mid+1)+1)-sum[rs];
        rev[ls]^=1;rev[rs]^=1;
        rev[rt]=0;
    }
}
void ins(int rt,int l,int r,int L,int R){
    if(L<=l&&r<=R){
        sum[rt]=(r-l+1)-sum[rt];
        rev[rt]^=1;
        return ;
    }
    down(rt,l,r);
    if(L<=mid)ins(ls,l,mid,L,R);
    if(mid<R)ins(rs,mid+1,r,L,R);
    up(rt);
}
int query(int rt,int l,int r,int L,int R){
    if(L<=l&&r<=R){
        return sum[rt];
    }down(rt,l,r);
    int ans=0;
    if(L<=mid)ans+=query(ls,l,mid,L,R);
    if(mid<R)ans+=query(rs,mid+1,r,L,R);
    return ans;
}
void dfs(int u,int f){
    ll[u]=++cnt;
    for(int i=0;i<g[u].size();++i){
        int v=g[u][i];
        if(v==f)continue;
        dfs(v,u);
    }
    rr[u]=cnt;
}
char op[22];
int main(){
    cnt=0;int n,u,v,m;scanf("%d",&n);
    
    for(int i=1;i<n;++i){
        scanf("%d%d",&u,&v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1,-1);
    build(1,1,n);
    scanf("%d",&m);
//    for(int i=1;i<=n;++i)printf("%d %d\n",ll[i],rr[i]);
    while(m--){
        scanf("%s%d",op,&u);
        if(*op=='Q')printf("%d\n",query(1,1,n,ll[u],rr[u]));
        else{
            ins(1,1,n,ll[u],rr[u]);
        }
    }
    return 0;
}