BZOJ1036: [ZJOI2008]树的统计Count

来源:互联网 发布:双开软件 编辑:程序博客网 时间:2024/04/18 16:37

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
树的分治

遥想当年我刚知道BZOJ的时候,迫切想做几道题一展身手,于是就专挑看得懂题面的题来做(无语了),于是。。。那时的我对于这道题交了一个O(n)的纯暴力(当时连时间复杂度都懒得算),而且好像还非常激动得写了个Tarjan求公共祖先,T掉之后愣了好久。。。
言归正传,此题做法:树的分治、树链剖分或动态树,好像还有分块的做法(ORZ)。我看着提示里面写着树的分治然后写了个树链剖分加线段树的做法,然后基本上就是模板了。
一定要注意询问同一个节点的情况(QMAX x x,QSUM x x),可以直接特判来解决。

#include<cstdio>#include<algorithm>#include<cstring>#define INF 2147483647using namespace std;const int N=30100;const int T=5000010;int n,m,q,w[N],point[N],next[2*N],to[2*N];int treenum,nodenum,deep[N],fa[N],son[N],size[N];int rank[N],top[N],belong[N];char opt[20];int root[N],lch[T],rch[T],treemax[T],treesum[T];void add(int u,int v){++m;next[m]=point[u];point[u]=m;to[m]=v;}void dfs(int u){    deep[u]=deep[fa[u]]+1;    int tmp=0;size[u]=1;    for (int i=point[u];i;i=next[i])    {        int v=to[i];        if (v!=fa[u])        {            fa[v]=u;dfs(v);size[u]+=size[v];            if (size[v]>tmp){tmp=size[v];son[u]=v;}        }    }    for (int i=point[u];i;i=next[i])    {        int v=to[i];        if (v==son[u])        {            belong[u]=belong[v];            rank[u]=rank[v]+1;        }        else top[belong[v]]=v;    }    if (son[u]==0)    {        belong[u]=++treenum;        rank[u]=1;    }}void updata(int now){    treemax[now]=max(treemax[lch[now]],treemax[rch[now]]);    treesum[now]=treesum[lch[now]]+treesum[rch[now]];}void build(int now,int l,int r){    treemax[now]=-INF;    if (l==r) return;    int mid=(l+r)>>1;    build(lch[now]=++nodenum,l,mid);    build(rch[now]=++nodenum,mid+1,r);}void change(int now,int l,int r,int loc,int v){    if (l==r)    {        treemax[now]=treesum[now]=v;        return;    }    int mid=(l+r)>>1;    if (loc<=mid) change(lch[now],l,mid,loc,v);    else change(rch[now],mid+1,r,loc,v);    updata(now);}int maxquery(int now,int l,int r,int lrange,int rrange){    if (lrange<=l&&r<=rrange) return treemax[now];    int mid=(l+r)>>1,ans=-INF;    if (lrange<=mid) ans=max(ans,maxquery(lch[now],l,mid,lrange,rrange));    if (rrange>mid) ans=max(ans,maxquery(rch[now],mid+1,r,lrange,rrange));    return ans;}int sumquery(int now,int l,int r,int lrange,int rrange){    if (lrange<=l&&r<=rrange) return treesum[now];    int mid=(l+r)>>1,ans=0;    if (lrange<=mid) ans+=sumquery(lch[now],l,mid,lrange,rrange);    if (rrange>mid) ans+=sumquery(rch[now],mid+1,r,lrange,rrange);    return ans;}int maxquery1(int u,int v){    int ans=-INF;    while(belong[u]!=belong[v])    {        if (deep[top[belong[u]]]>deep[top[belong[v]]])        {            ans=max(ans,maxquery(root[belong[u]],1,rank[top[belong[u]]],rank[u],rank[top[belong[u]]]));            u=fa[top[belong[u]]];        }        else        {            ans=max(ans,maxquery(root[belong[v]],1,rank[top[belong[v]]],rank[v],rank[top[belong[v]]]));            v=fa[top[belong[v]]];        }    }    ans=max(ans,maxquery(root[belong[u]],1,rank[top[belong[u]]],min(rank[u],rank[v]),max(rank[u],rank[v])));    return ans;}int sumquery1(int u,int v){    int ans=0;    while(belong[u]!=belong[v])    {        if (deep[top[belong[u]]]>deep[top[belong[v]]])        {            ans+=sumquery(root[belong[u]],1,rank[top[belong[u]]],rank[u],rank[top[belong[u]]]);            u=fa[top[belong[u]]];        }        else        {            ans+=sumquery(root[belong[v]],1,rank[top[belong[v]]],rank[v],rank[top[belong[v]]]);            v=fa[top[belong[v]]];        }    }    ans+=sumquery(root[belong[u]],1,rank[top[belong[u]]],min(rank[u],rank[v]),max(rank[u],rank[v]));    return ans;}void work(){    dfs(1);top[belong[1]]=1;    for (int i=1;i<=treenum;++i)    {        root[i]=++nodenum;        build(root[i],1,rank[top[i]]);    }    for (int i=1;i<=n;++i)    change(root[belong[i]],1,rank[top[belong[i]]],rank[i],w[i]);}int main(){    scanf("%d",&n);int x,y;    for (int i=1;i<n;++i)    {        scanf("%d%d",&x,&y);        add(x,y);add(y,x);    }    for (int i=1;i<=n;++i) scanf("%d",&w[i]);    work();scanf("%d",&q);    for (;q;--q)    {        scanf("%s",opt+1);scanf("%d%d",&x,&y);        if (opt[1]=='C') change(root[belong[x]],1,rank[top[belong[x]]],rank[x],y);        else if (opt[2]=='M') printf("%d\n",maxquery1(x,y));        else printf("%d\n",sumquery1(x,y));    }    return 0;}
0 0