Hdu 5221 Occupation

算是一个简单的树剖+线段树(不过话说回来树剖也是经常和线段树一起(这个题应该叫做线段树在树上的简单应用(Orz


感觉自己的线段树(特别是区间更新这个地方)还是很不熟练
(观看下文需要一些简单的线段树知识,包括但不限于线段树的定义)


如果不考虑树上的部分的话,这个题要求我们维护一个区间,其中区间中的每一个点都有一个标记和一个value,刚开始的时候,标记都是false
1 将区间[L,R]上所有没有标记的点都标记上
2 将u这个点的标记取消掉
3 询问区间[1,n]上被标记的所有点的权值和


(显然这个题要用到lazy标记(这不是废话吗,线段树什么区间更新的题不用lazy标记的(╯‵□′)╯︵┻━┻


定义lazy[o]==1时表示这个节点的区间是全部被标记的,这个节点的val就是区间和(也就是他的子节点的状态我们都能知道,虽然子节点的val和lazy是不定的,但是会被这一次操作覆盖)我们不知道是不是全部被标记的时候,lazy[o]都为0
随手维护一下前缀和(sum)


操作1好像就变得很简单了
我们只要在当前的区间被标记的区间完全覆盖的时候,把当前的lazy变成1,val[o]=sum[r]-sum[l-1]


然后看操作2


单点更新还是很简单的嗯
唯一需要注意的是如果在更新的路上碰到lazy[o]==1的情况,把这个状态push下去
然后在更新完之后维护一下就好


3的话就是根节点的val了(因为我们每次update之后都维护到了根节点


线段树的部分还是很简单的


然而有眼尖的同学会问,这个题不是要标记一个子树吗QAQ,子树怎么做呀,树链剖分好像不能处理子树的情况啊QAQQQQ


咳咳,仔细回忆一下,是不是有一个神奇的性质(并不),一个子树的dfs序是连续的!


(⊙v⊙)


还有什么问题吗






-------------------------我是代码的分割线-------------------

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")

const int maxn = 112345;


#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define Mid int m = (l+r)>>1
#define root 1,1,n
#define Now int o,int l,int r

#define LL long long

int arr[maxn];
int aar[maxn];
LL sum[maxn];
int lazy[maxn*4];
LL val[maxn*4];

void sinit(int n){
    memset(lazy,0,sizeof(lazy));
    memset(val,0,sizeof(val));
    sum[0]=0;
    for(int i=1;i<=n;i++){
        sum[i]=sum[i-1]+arr[i];
    }
}

void maintain(Now){
    lazy[o]=1;
    val[o]=sum[r]-sum[l-1];
}

void update(Now,int ul,int ur){
    if(ul<=l && r<=ur){
        maintain(o,l,r);
        return;
    }
    Mid;
    if(lazy[o]==1){
        return;
    }
    if(ul<=m)
        update(lson,ul,ur);
    if(m+1<=ur)
        update(rson,ul,ur);
    val[o]=val[o<<1]+val[o<<1|1];
}

void update(Now,int pos){
  //  printf("pos = %d\n",pos);
    if(l==r){
        lazy[o]=val[o]=0;
        return;
    }
    Mid;
    if(lazy[o]==1){
        lazy[o]=0;
        maintain(lson);
        maintain(rson);
    }
    if(pos<=m)
        update(lson,pos);
    else
        update(rson,pos);
    val[o]=val[o<<1]+val[o<<1|1];
}


vector<int> edge[maxn];

void init(int n){
    for(int i=0;i<=n;i++)
        edge[i].resize(0);
}

void Link(int st,int ed){
    edge[st].push_back(ed);
    edge[ed].push_back(st);
}

int fa[maxn],son[maxn],tid[maxn],siz[maxn],top[maxn],deep[maxn];
int _cnt;

void dffs(int st,int Fa,int Deep){
    deep[st]=Deep,son[st]=-1,siz[st]=1,fa[st]=Fa;
    for(auto & x:edge[st]){
        if(x!=Fa){
            dffs(x,st,Deep+1);
            siz[st]+=siz[x];
            if(son[st]==-1 || siz[son[st]]<siz[x])
                son[st]=x;
        }
    }
}

void dfss(int st,int Top){
    tid[st]=_cnt++,top[st]=Top;
    if(son[st]!=-1)
        dfss(son[st],Top);
    for(auto & x:edge[st]){
        if(x!=fa[st] && x!=son[st]){
            dfss(x,x);
        }
    }
}

void tinit(){
    _cnt=1;
    dffs(1,0,1);
    dfss(1,1);
}


void UPD(int x,int y,int n){
    int tx = top[x],ty=top[y];
    while(tx!=ty){
        if(deep[tx] > deep[ty]){ // up  x
            update(root,tid[tx],tid[x]);
            x=fa[tx],tx=top[x];
        }
        else{
            update(root,tid[ty],tid[y]);
            y=fa[ty],ty=top[y];
        }
 //   printf("x = %d y = %d\n",x,y);
    }
    if(deep[x]>deep[y]){
        update(root,tid[y],tid[x]);
    }
    else{
        update(root,tid[x],tid[y]);
    }
}

void UPD(int x,int n){
    int id = tid[x];
    int size = siz[x];
    update(root,id,id+size-1);
}

int main(){
    int n,m;
    int T;
    scanf("%d",&T);
    while(T-- && ~scanf("%d",&n)){
        for(int i=1;i<=n;i++)
            scanf("%d",&aar[i]);
        int u,v;
        init(n);
        for(int i=1;i<n;i++){
            scanf("%d %d",&u,&v);
            Link(u,v);
        }
        tinit();
        for(int i=1;i<=n;i++){
            arr[tid[i]]=aar[i];
        }
//        for(int i=1;i<=n;i++)
//            printf(i<n?"%d ":"%d\n",tid[i]);
//        for(int i=1;i<=n;i++)
//            printf(i<n?"%d ":"%d\n",top[i]);
        sinit(n);
        scanf("%d",&m);
        int ord;
        while(m--){
            scanf("%d",&ord);
            if(ord==1){
                scanf("%d %d",&u,&v);
                UPD(u,v,n);
            }
            else if(ord==2){
                scanf("%d",&u);
                update(root,tid[u]);
            }
            else{
                scanf("%d",&u);
                UPD(u,n);
            }
            printf("%lld\n",val[1]);
        }
    }
    return 0;
}


/*
1
10
1 2 3 4 5 6 7 8 9 10
1 2
1 3
2 4
2 5
5 9
5 10
3 6
3 7
3 8
6
1 10 4
1 9 7
2 5
3 4
2 4
1 6 10


1
5
5 5 5 5 5
1 2
1 3
1 4
1 5
10086
3 1


10086
2
1 10
1 2
10086

*/



你可能感兴趣的:(Hdu 5221 Occupation)