HDU5221 Occupation【树链剖分+线段树】

题意:有三种操作,1代表占领u-v这条路径上的所有点,2表示失去u这个点,3占领以u为根的子树的所有点。。对每一个询问输出他占领城市的权值之和。。

首先树链剖分处理一下,然后用线段树维护区间求和区间查询就好了,查询过的点再置0。。。

处理子树可以根据dfs序来求,可以在树链剖分的时候记录下这个点的dfs序,然后查询子树就可以直接有一个区间了。

1操作没有想到处理一个点的时候错了。。wa了几次

#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ls (k<<1)
#define rs (k<<1|1)
using namespace std;
const int MAXN=100010;
int fa[MAXN],w[MAXN],siz[MAXN],son[MAXN],dep[MAXN],top[MAXN],in[MAXN],out[MAXN];
int w1[MAXN];
int totw,dfs_clock;
struct EDGE
{
    int v,next;
}edge[MAXN<<1];
int head[MAXN],size;
void init()
{
    memset(head,-1,sizeof(head));
    memset(son,-1,sizeof(son));
    memset(fa,-1,sizeof(fa));
    memset(dep,0,sizeof(dep));
    size=0;
    totw=0;
    dfs_clock=0;
}
void add_edge(int u,int v)
{
    edge[size].v=v;
    edge[size].next=head[u];
    head[u]=size++;
}
void dfs1(int u,int f,int deep)	//dfs求出siz,son,fa,dep
{
    siz[u]=1;
    int mmax=-1;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==f)
            continue;
        fa[v]=u;
        dep[v]=dep[u]+1;
        dfs1(v,u,deep+1);
        siz[u]+=siz[v];
        if(siz[v]>mmax)
        {
            mmax=siz[v];
            son[u]=v;
        }
    }
}
void dfs2(int u,int f)	//求出w,top
{
    in[u]=++dfs_clock;
    top[u]=f;
    totw++;
    w[u]=totw;
    w1[totw]=u;
    if(son[u]!=-1)
        dfs2(son[u],f);
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v!=son[u]&&v!=fa[u])
            dfs2(v,v);
    }
    out[u]=dfs_clock;
}
int val[MAXN];
struct TREE
{
    int l,r;
    int sum;
    int mark,val;
    int mid()
    {
        return (l+r)>>1;
    }
}tree[MAXN<<2];
void pushup(int k)
{
    tree[k].sum=tree[ls].sum+tree[rs].sum;
}
void pushdown(int k)
{
    if(tree[k].mark!=-1)
    {
        tree[ls].sum=tree[rs].sum=tree[k].val;
        tree[ls].val=tree[rs].val=tree[k].val;
        tree[ls].mark=tree[rs].mark=tree[k].mark;
        tree[k].mark=-1;
    }
}
void build(int l,int r,int k)
{
    tree[k].l=l;
    tree[k].r=r;
    tree[k].mark=-1;
    tree[k].val=0;
    if(l==r)
    {
        tree[k].sum=val[w1[l]];
        return;
    }
    int mid=tree[k].mid();
    build(l,mid,ls);
    build(mid+1,r,rs);
    pushup(k);
}
void update(int l,int r,int k,int v)
{
    if(tree[k].l>=l&&tree[k].r<=r)
    {
        tree[k].sum=v;
        tree[k].val=v;
        tree[k].mark=0;
        return;
    }
    pushdown(k);
    int mid=tree[k].mid();
    if(r<=mid)
        update(l,r,ls,v);
    else if(l>mid)
        update(l,r,rs,v);
    else
    {
        update(l,mid,ls,v);
        update(mid+1,r,rs,v);
    }
    pushup(k);
}
int query(int l,int r,int k)
{
    if(tree[k].l>=l&&tree[k].r<=r)
        return tree[k].sum;
    pushdown(k);
    int mid=tree[k].mid();
    if(r<=mid)
        return query(l,r,ls);
    else if(l>mid)
        return query(l,r,rs);
    else
        return query(l,mid,ls)+query(mid+1,r,rs);
}
int ans;
void update1(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
            swap(x,y);
        ans+=query(w[top[x]],w[x],1);
        update(w[top[x]],w[x],1,0);
        x=fa[top[x]];
    }
    if(x==y)
    {
    	ans+=query(w[x],w[x],1);
    	update(w[x],w[x],1,0);
    	return;
    }
    if(dep[x]>dep[y])
        swap(x,y);
    ans+=query(w[x],w[y],1);
    update(w[x],w[y],1,0);
}
void update2(int u)
{
    if(query(w[u],w[u],1)==0)
    {
        update(w[u],w[u],1,val[u]);
        ans-=val[u];
    }
}
void update3(int x)
{
    int l=in[x];
    int r=out[x];
    ans+=query(l,r,1);
    update(l,r,1,0);
}
int main()
{
    int t,n,i;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=1;i<=n;i++)
            scanf("%d",&val[i]);
        init();
        int u,v;
        for(i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            add_edge(u,v);
            add_edge(v,u);
        }
        int q;
        dfs1(1,-1,0);
        dfs2(1,1);
        build(1,totw,1);
        scanf("%d",&q);
        ans=0;
        while(q--)
        {
            int op;
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%d%d",&u,&v);
                update1(u,v);
            }
            else if(op==2)
            {
                scanf("%d",&u);
                update2(u);
            }
            else
            {
                scanf("%d",&u);
                update3(u);
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}
/*
2
7
1 2 3 4 5 6 7
1 2
2 3
3 6
3 7
3 4
4 5
100
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值