当前位置:编程学习 > C/C++ >>

hdu 3966 (树链剖分+线段树)

题意:给出一棵树,每个节点有一些敌人,有三种操作,I:x,y,路径上的所有点的人数+w。D:x,y,路径上的所有点的人数-w。Q:节点x的人数。
思路:如果是线性的线段树可以做,所以要树链剖分,剖分后的每条链是线性的,更改区间时用找公共祖先的方式,将两点找到同一条链上,同一条链上的两点间可以直接线段树更改。
 
 
 
 
 
#pragma comment(linker, "/STACK:1024000000,1024000000")  
#include<stdio.h>  
#include<string.h>  
#include <iostream>  
using namespace std;  
const int N=51000;  
int son[N],sz[N],dep[N],top[N],father[N],head[N],ti[N],num,idx,a[N];  
struct edge  
{  
    int ed,next;  
}e[N*4];  
void addedge(int x,int y)  
{  
    e[num].ed=y;e[num].next=head[x];head[x]=num++;  
    e[num].ed=x;e[num].next=head[y];head[y]=num++;  
}  
//*******************树链剖分**********************  
void find_son(int u)  
{  
    int i,v;  
    sz[u]=1;son[u]=0;  
    for(i=head[u];i!=-1;i=e[i].next)  
    {  
        v=e[i].ed;  
        if(v==father[u])continue;  
        father[v]=u;dep[v]=dep[u]+1;  
        find_son(v);  
        sz[u]+=sz[v];  
        if(sz[v]>sz[son[u]])son[u]=v;  
    }  
}  
void find_time(int u,int fa)  
{  
    int i,v;  
    ti[u]=idx++;      
    top[u]=fa;  
    if(son[u]!=0)find_time(son[u],top[u]);  
    for(i=head[u];i!=-1;i=e[i].next)  
    {  
        v=e[i].ed;  
        if(v==son[u]||v==father[u])continue;  
        find_time(v,v);  
    }  
}  
//************************线段树**************************  
struct Tree  
{  
    int R,L,ct;//ct:该区间的增量  
}T[N*4];  
void buildTree(int L,int R,int id)  
{  
    T[id].L=L;T[id].R=R;T[id].ct=0;  
    if(L==R) return ;         
    int mid=(L+R)>>1,li=id<<1,ri=li+1;  
    buildTree(L,mid,li);  
    buildTree(mid+1,R,ri);  
}  
void insert(int L,int R,int id,int w)  
{  
    if(T[id].L==L&&T[id].R==R)  
    {  
        T[id].ct+=w;  
        return ;  
    }  
    int mid=(T[id].L+T[id].R)>>1,li=id<<1,ri=li+1;  
    if(mid>=R)insert(L,R,li,w);  
    else if(mid<L)insert(L,R,ri,w);  
    else   
    {  
        insert(L,mid,li,w);  
        insert(mid+1,R,ri,w);  
    }  
}  
int find(int i,int id,int w)  
{  
    if(T[id].L==T[id].R)  
        return w+T[id].ct;  
    int mid=(T[id].L+T[id].R)>>1,li=id<<1,ri=li+1;  
    if(mid>=i)return find(i,li,w+T[id].ct);  
    else return find(i,ri,w+T[id].ct);  
}  
void lca(int x,int y,int w)  
{  
    while(top[x]!=top[y])  
    {  
        if(dep[top[x]]<dep[top[y]])swap(x,y);  
        insert(ti[top[x]],ti[x],1,w);  
        x=father[top[x]];  
    }  
    if(dep[x]>dep[y])swap(x,y);  
    insert(ti[x],ti[y],1,w);  
}  
int main()  
{  
    int i,n,m,q,x,y,w;  
    char str[10];  
    while(scanf("%d%d%d",&n,&m,&q)!=-1)  
    {  
        memset(head,-1,sizeof(head));  
        num=0;  
        for(i=1;i<=n;i++)  
            scanf("%d",&a[i]);  
        for(i=1;i<=m;i++)  
        {  
            scanf("%d%d",&x,&y);  
            addedge(x,y);  
        }  
        father[1]=sz[0]=0;dep[1]=idx=1;  
        find_son(1);  
        find_time(1,1);  
        buildTree(1,n,1);  
        while(q--)  
        {  
            scanf("%s",str);  
            if(str[0]=='Q')  
            {  
                scanf("%d",&x);  
                printf("%d\n",a[x]+find(ti[x],1,0));  
            }  
            else  
            {  
                scanf("%d%d%d",&x,&y,&w);  
                if(str[0]=='I') w=-w;                 
                lca(x,y,-w);  
            }  
        }  
    }  
    return 0;  
}  

 

 
 
补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,