"BestCoder"杯中国大学生程序设计冠军赛 HDU 5221 Occupation

题目链接~~>

做题感悟 :区域赛过后就没写过树剖 ,只记得思想,比赛时想到了,但是只打代码就打了半个多小时(真是醉了!!),然后就是不断的调试代码,悲催的是调了一个多小时也没调出来。。。。。

解题思路:这题只要想到某个节点的子树的所有节点编号都大于此节点的编号(在线段树中的位置的编号,树剖的时候编号都是连续的)且是连续的,那么我们只要深搜的时候记录一下子树最大的一个子节点的时间戳(在线段树中的编号),只要我们利用一个节点的进去的时间戳和出去的时间戳就可以对这个节点的子树操作了(CF上有一个处理子树类似的题),其它的两个操作就 so easy 了,线段树写的很挫,请见谅。。。

代码:

#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <string.h>
#include <math.h>
#include <queue>
#include <algorithm>
#include <stdlib.h>
#include <map>
#include <set>
#include <stdio.h>
#include <vector>
#define L(x) (x*2)
#define R(x) (x*2 + 1)
using namespace std;

const int INF = 0x3f3f3f3f ;
const int MX = 100000 + 5 ;
int n ,m ,num ,idx ,sum ;
int dep[MX] ,top[MX] ,V[MX] ,ti[MX] ,to[MX] ,head[MX] ,father[MX] ,siz[MX] ,son[MX] ;

struct Edge
{
    int v ,next ;
}E[MX*2] ;
void add_edge(int u ,int v)
{
    E[num].v = v ; E[num].next = head[u] ; head[u] = num++ ;
    E[num].v = u ; E[num].next = head[v] ; head[v] = num++ ;
}
void dfs_find(int u ,int fa)
{
    dep[u] = dep[fa] + 1 ;
    father[u] = fa ;
    siz[u] = 1 ;
    son[u] = 0 ;
    for(int i = head[u] ;i != -1 ; i = E[i].next)
    {
        int v = E[i].v ;
        if(v == fa)  continue ;
        dfs_find(v ,u) ;
        siz[u] += siz[v] ;
        if(siz[son[u]] < siz[v])   son[u] = v ;
    }
}
void dfs_time(int u ,int fa)
{
    ti[u] = idx++ ;
    top[u] = fa ;
    if(son[u])  dfs_time(son[u] ,top[u]) ;
    for(int i = head[u] ;i != -1 ;i = E[i].next)
    {
        int v = E[i].v ;
        if(v == father[u] || v == son[u])  continue ;
        dfs_time(v ,v) ;
    }
    to[u] = idx-1 ;
}
void init()
{
    sum = 0 ;
    num = 0 ;
    memset(head ,-1 ,sizeof(head)) ;
}
//线段树  ---------------------
struct node
{
    int le ,rt ,sum ,flag ;
}T[MX*4] ;
void build(int x ,int le ,int rt)
{
    T[x].sum = 0 ;
    T[x].flag = true ;
    T[x].le = le ; T[x].rt = rt ;
    if(le == rt)
               return ;
    int Mid = (le + rt)>>1 ;
    build(L(x) ,le ,Mid) ;
    build(R(x),Mid+1 ,rt) ;
}
void push_up(int x)
{
    T[x].sum = T[L(x)].sum + T[R(x)].sum  ;
    T[x].flag = true ;
}
void push_down(int x)
{
    if(!T[x].flag)
    {
        T[L(x)].sum = T[R(x)].sum = 0 ;
        T[L(x)].flag = T[R(x)].flag = false ;
        T[x].sum = 0 ;
    }
}
bool Findpos(int x ,int pos)
{
    if(T[x].le == T[x].rt && T[x].le == pos)
    {
        if(!T[x].flag)  T[x].sum = 0 ;
        return T[x].flag ;
    }
    push_down(x) ;
    int Mid = (T[x].le + T[x].rt)>>1 ;
    if(pos <= Mid)   return Findpos(L(x) ,pos) ;
    else    return Findpos(R(x) ,pos) ;
    push_up(x) ;
}
void insert(int x ,int pos ,int w)  // 修改点
{
     if(T[x].le == T[x].rt && T[x].le == pos)
     {
         T[x].sum = w ;
         T[x].flag = true ;
         return ;
     }
     push_down(x) ;
     int Mid = (T[x].le + T[x].rt)>>1 ;
     if(pos <= Mid)  insert(L(x) ,pos ,w) ;
     else    insert(R(x) ,pos ,w) ;
     push_up(x) ;
}
void update(int x ,int Le ,int Rt) // 区间清零
{
    if(T[x].le == Le && T[x].rt == Rt)
    {
        T[x].flag = false ;
        T[x].sum = 0 ;
        return ;
    }
    push_down(x) ;
    int Mid = (T[x].le + T[x].rt)>>1 ;
    if(Le > Mid)   update(R(x) ,Le ,Rt) ;
    else if(Rt <= Mid)  update(L(x) ,Le ,Rt) ;
    else
    {
        update(L(x) ,Le ,Mid) ;
        update(R(x) ,Mid+1 ,Rt) ;
    }
    push_up(x) ;
}
int Query(int x ,int Le ,int Rt) // 区间求和
{
   if(T[x].le == Le && T[x].rt == Rt)
    {
        if(!T[x].flag)  T[x].sum = 0 ;
        int temp = T[x].sum ;
        T[x].sum = 0 ;
        T[x].flag = false ;
        return temp ;
    }
    push_down(x) ;
    int Mid = (T[x].le + T[x].rt)>>1 ;
    if(Le > Mid)   return Query(R(x) ,Le ,Rt) ;
    else if(Rt <= Mid)  return Query(L(x) ,Le ,Rt) ;
    else
        return Query(L(x) ,Le ,Mid) + Query(R(x) ,Mid+1 ,Rt) ;
}
void LCA(int u ,int v)
{
    int temp ;
    while(top[u] != top[v])
    {
        if(dep[top[u]] < dep[top[v]])
             swap(u ,v) ;
        temp = Query(1 ,ti[top[u]] ,ti[u]) ;
        update(1 ,ti[top[u]] ,ti[u]) ;
        sum += temp ;
        u = father[top[u]] ;
    }
    if(dep[u] > dep[v])
         swap(u ,v) ;
    temp = Query(1 ,ti[u] ,ti[v]) ;
    update(1 ,ti[u] ,ti[v]) ;
    sum += temp ;
}
int main()
{
    //freopen("input.txt" ,"r" ,stdin) ;
    int Tx ,u ,v ;
    scanf("%d" ,&Tx) ;
    while(Tx--)
    {
        init() ;
        scanf("%d" ,&n) ;
        for(int i = 1 ;i <= n ; ++i)
            scanf("%d" ,&V[i]) ;
        for(int i = 1 ;i < n ; ++i)
        {
            scanf("%d%d" ,&u ,&v) ;
            add_edge(u ,v) ;
        }
        dep[1] = siz[0] = 0 ;
        dfs_find(1 ,1) ;
        idx = 1 ;
        dfs_time(1 ,1) ;
        build(1 ,1 ,n) ;
        for(int i = 1 ;i <= n ; ++i)
            insert(1 ,ti[i] ,V[i]) ;
        scanf("%d" ,&m) ;
        int type ;
        for(int i = 0 ;i < m ; ++i)
        {
            scanf("%d%d" ,&type ,&u) ;
            if(type == 1)
            {
                scanf("%d" ,&v) ;
                LCA(u ,v) ;
            }
            else if(type == 2)
            {
                bool flag = Findpos(1 ,ti[u]) ;
                if(!flag) // 如果为 false 说明已经被占据
                {
                    insert(1 ,ti[u] ,V[u]) ;
                    sum -= V[u] ;
                }
            }
            else if(type == 3)
            {
                sum += Query(1 ,ti[u] ,to[u]) ;
                update(1 ,ti[u] ,to[u]) ;
            }
            cout<<sum<<endl ;
        }
    }
    return 0 ;
}


猜你喜欢

转载自blog.csdn.net/u011074149/article/details/45457685