动态树||树链剖分(BZOJ1036)

来源:互联网 发布:c语言 char负值 编辑:程序博客网 时间:2024/06/06 06:46

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 7051  Solved: 2872
[Submit][Status][Discuss]

Description

一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

Input

输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

Output

对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

Sample Input

4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4

Sample Output

4
1
2
2
10
6
5
6
5
16

HINT

Source

树的分治


思路:因为操作的是点权。所以可以直接把其中一个变成根,然后接着搞,要是边权的话,就不行了,就要按照LCA那样高了

这个题也可以用树链剖分写



#include<iostream>#include<cstdio>#include<string>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<stack>#include<map>#include<set>#include<algorithm>using namespace std;const int maxn=30010;const int INF=1000000000;int N,Q;struct node{    int v,next;}edge[maxn*2];int head[maxn];int tot;void add_edge(int u,int v){    edge[tot].v=v;    edge[tot].next=head[u];    head[u]=tot++;}struct LCT{    int ch[maxn][2],pre[maxn],key[maxn];    int rev[maxn],maxv[maxn];    bool rt[maxn];    int sum[maxn];    void update_rev(int r)    {        if(!r)return;        swap(ch[r][0],ch[r][1]);        rev[r]^=1;    }    void pushdown(int r)    {        if(rev[r])        {            update_rev(ch[r][1]);            update_rev(ch[r][0]);            rev[r]=0;        }    }    void pushup(int r)    {        maxv[r]=max(max(maxv[ch[r][0]],maxv[ch[r][1]]),key[r]);        sum[r]=sum[ch[r][0]]+sum[ch[r][1]]+key[r];    }    void rotate(int x)    {        int y=pre[x],kind=ch[y][1]==x;        ch[y][kind]=ch[x][!kind];        pre[ch[y][kind]]=y;        pre[x]=pre[y];        pre[y]=x;        ch[x][!kind]=y;        if(rt[y])rt[y]=false,rt[x]=true;        else ch[pre[x]][ch[pre[x]][1]==y]=x;        pushup(y);    }    //将根节点到r的路径上的所有及诶单的标记下方    void P(int r)    {        if(!rt[r])P(pre[r]);        pushdown(r);    }    void Splay(int r)    {        P(r);        while(!rt[r])        {            int f=pre[r],ff=pre[f];            if(rt[f])rotate(r);            else if((ch[ff][1]==f)==(ch[f][1]==r))                rotate(f),rotate(r);            else rotate(r),rotate(r);        }        pushup(r);    }    int Access(int x)    {        int y=0;        for(;x;x=pre[y=x])        {            Splay(x);            rt[ch[x][1]]=true,rt[ch[x][1]=y]=false;            pushup(x);        }        return y;    }     int getroot(int x)     {        Access(x);        Splay(x);        while (ch[x][0])            x = ch[x][0];        return x;    }    //判断是否同根    bool judge(int u,int v)    {        while(pre[u])u=pre[u];        while(pre[v])v=pre[v];        return u==v;    }    //将r变成他所在根    void mroot(int r)    {        Access(r);        Splay(r);        update_rev(r);    }    //调用后u是原来u和v的lca,v和ch[u][1]分别存折lca的两个儿子    void lca(int &u,int &v)    {        Access(v),v=0;        while(u)        {            Splay(u);            if(!pre[u])return;            rt[ch[u][1]]=true;            rt[ch[u][1]=v]=false;            pushup(u);            u=pre[v=u];        }    }    //将u合并到v上    void link(int u,int v)    {        mroot(u);        pre[u]=v;    }    //将v和他的父节点分离    void cut(int v)    {        //mroot(v);        Access(v);        Splay(v);        pre[ch[v][0]]=0;        pre[v]=0;        rt[ch[v][0]]=true;        ch[v][0]=0;        pushup(v);    }    void init()    {        memset(head,-1,sizeof(head));        memset(pre,0,sizeof(pre));        memset(ch,0,sizeof(ch));        memset(rev,0,sizeof(rev));        memset(sum,0,sizeof(sum));        for(int i=0;i<=N;i++)rt[i]=true;        maxv[0]=-INF;    }    void dfs(int u,int f)    {        for(int i=head[u];i!=-1;i=edge[i].next)        {            int v=edge[i].v;            if(v==f)continue;            pre[v]=u;            dfs(v,u);        }    }}tree;int main(){    int u,v;    char op[10];    while(scanf("%d",&N)!=EOF)    {        tree.init();        for(int i=1;i<N;i++)        {            scanf("%d%d",&u,&v);            add_edge(u,v);            add_edge(v,u);        }        for(int i=1;i<=N;i++)scanf("%d",&tree.key[i]);        tree.dfs(1,0);        scanf("%d",&Q);        while(Q--)        {            scanf("%s%d%d",op,&u,&v);//cout<<op<<endl;            if(op[0]=='C')            {                tree.Access(u);                tree.Splay(u);                tree.key[u]=v;                tree.pushup(u);            }            else if(op[1]=='M')            {                //注意一下三个操作的顺序                tree.mroot(u);                tree.Access(v);                tree.Splay(u);                printf("%d\n",tree.maxv[u]);            }            else            {                tree.mroot(u);                tree.Access(v);                tree.Splay(u);                //tree.Splay(v);                printf("%d\n",tree.sum[u]);            }        }    }    return 0;}

树链剖分写发(转自http://www.cnblogs.com/silver-bullet/archive/2013/02/09/2909473.html):

#include<cstdio>#include<cstring>#include<algorithm>#define N 30010#define lson l,m,n<<1#define rson m+1,r,n<<1|1using namespace std;const int inf=1<<30;struct Edge{    int u,v,next;    Edge(){}    Edge(int _u,int _v,int _next){        u=_u;v=_v;next=_next;    }}edge[N<<1];int head[N],cnt;int sz[N],top[N],fa[N],dep[N],hash[N],w[N],son[N],num;void init(){    memset(head,-1,sizeof(head));    cnt=num=0;}void add(int u,int v){    edge[cnt]=Edge(u,v,head[u]);head[u]=cnt++;    edge[cnt]=Edge(v,u,head[v]);head[v]=cnt++;}void dfs(int u,int d){    sz[u]=1;son[u]=0;dep[u]=d;    for(int k=head[u];k!=-1;k=edge[k].next){        int v=edge[k].v;        if(v==fa[u])continue;        fa[v]=u;        dfs(v,d+1);        sz[u]+=sz[v];        if(sz[v]>sz[son[u]])son[u]=v;    }}void build_tree(int u,int pre){    hash[u]=++num;top[u]=pre;    if(son[u])build_tree(son[u],pre);    for(int k=head[u];k!=-1;k=edge[k].next){        int v=edge[k].v;        if(v!=fa[u]&&v!=son[u])build_tree(v,v);    }}struct segtree{    int maxn[N<<2],sum[N<<2];    void pushup(int n){        sum[n]=sum[n<<1]+sum[n<<1|1];        maxn[n]=max(maxn[n<<1],maxn[n<<1|1]);    }    void update(int nn,int x,int l,int r,int n){        if(l==r){            maxn[n]=sum[n]=x;            return;        }        int m=(l+r)>>1;        if(nn<=m)update(nn,x,lson);        else update(nn,x,rson);        pushup(n);    }    int query_max(int ll,int rr,int l,int r,int n){        if(ll==l&&rr==r)return maxn[n];        int m=(l+r)>>1;        if(rr<=m)return query_max(ll,rr,lson);        else if(ll>m)return query_max(ll,rr,rson);        else return max(query_max(ll,m,lson),query_max(m+1,rr,rson));    }    int query_sum(int ll,int rr,int l,int r,int n){        if(ll==l&&rr==r)return sum[n];        int m=(l+r)>>1;        if(rr<=m)return query_sum(ll,rr,lson);        else if(ll>m)return query_sum(ll,rr,rson);        else return query_sum(ll,m,lson)+query_sum(m+1,rr,rson);    }}seg;int Query_max(int a,int b,int n){    int ta=top[a],tb=top[b],ans=-inf;    while(ta!=tb){        if(dep[ta]<dep[tb]){            swap(ta,tb);swap(a,b);        }        ans=max(ans,seg.query_max(hash[ta],hash[a],1,n,1));        a=fa[ta];ta=top[a];    }    if(dep[a]>dep[b])swap(a,b);    return max(ans,seg.query_max(hash[a],hash[b],1,n,1));}int Query_sum(int a,int b,int n){    int ta=top[a],tb=top[b],ans=0;    while(ta!=tb){        if(dep[ta]<dep[tb]){            swap(ta,tb);swap(a,b);        }        ans+=seg.query_sum(hash[ta],hash[a],1,n,1);        a=fa[ta];ta=top[a];    }    if(dep[a]>dep[b])swap(a,b);    return ans+seg.query_sum(hash[a],hash[b],1,n,1);}int main(){    int n,a,b,q;    char op[10];    while(~scanf("%d",&n)){        init();        for(int i=1;i<n;i++){            scanf("%d%d",&a,&b);            add(a,b);        }        for(int i=1;i<=n;i++)scanf("%d",&w[i]);        dfs(1,1);        build_tree(1,1);        for(int i=1;i<=n;i++)seg.update(hash[i],w[i],1,n,1);        scanf("%d",&q);        while(q--){            scanf("%s%d%d",op,&a,&b);            if(strcmp(op,"QMAX")==0){                int ans=Query_max(a,b,n);                printf("%d\n",ans);            }else if(strcmp(op,"QSUM")==0){                int ans=Query_sum(a,b,n);                printf("%d\n",ans);            }else {                seg.update(hash[a],b,1,n,1);            }        }    }    return 0;}


0 0
原创粉丝点击