WOJ2232 树上修改4(方法同上上篇,树剖)

【题目描述】

有n个节点N-1条边,这是一颗树,有2个操作:

1 x v:表示将节点x的权值+v

2 x y:表示查询x到y的路径权值和

【输入格式】

第一行是数N,表示N个节点,接下一行是n个数,表示每个节点的初始权值。

接下来n-1行,每行描述了n-1条边。

接下来是一个数q表示有q次查询与询问 接下来q行,格式如题

【输出格式】

对于每次询问,输出路径权值和。

【样例输入】

3

1 2 3

1 2

2 3

3

1 1 2 

1 2 3 

2 1 3

【样例输出】

11

【题目分析】

BZOJ1036树的统计题解传送门:https://blog.csdn.net/g21glf/article/details/82956343

我的天,这两道题基本没区别啊!!!取了一个最大值,改了一下路径修改方式,就是一道题了。。。所以照搬啦

【代码~】

#include<bits/stdc++.h>
using namespace std;
const int MAXN=3e5+10;

struct node{
    int y,next;
}edge[MAXN<<1];

int head[MAXN];
int dfn[MAXN],son[MAXN],depth[MAXN],fa[MAXN],siz[MAXN],a[MAXN];
int l,x,y,n,q,tot;
char s[10];
int rec[MAXN],top[MAXN];

void add(int x,int y)
{
    l++;
    edge[l].y=y;
    edge[l].next=head[x];
    head[x]=l;
}

void dfs1(int x,int f)
{
    fa[x]=f;
    son[x]=0;
    siz[x]=1;
    for(int i=head[x];i!=-1;i=edge[i].next)
    {
    	int v=edge[i].y;
        if(v!=f)
        {
            depth[v]=depth[x]+1;
            dfs1(v,x);
            siz[x]+=siz[v];
            if(siz[son[x]]<siz[v])
              son[x]=v;
        }
    }
}

void dfs2(int x,int tp)
{
    top[x]=tp;
    dfn[x]=++tot;
    rec[dfn[x]]=x;
    if(son[x]) 
	  dfs2(son[x],tp);
    for(int i=head[x];i!=-1;i=edge[i].next)
    {
    	int v=edge[i].y;
     	if(v!=fa[x]&&v!=son[x])
     	  dfs2(v,v);
 	}
}

struct point{
    int l,r,sum;
}tr[4*MAXN];

void push_up(int root)
{
    tr[root].sum=tr[root<<1].sum+tr[root<<1|1].sum;
}

void build(int root,int l,int r)
{
    tr[root].l=l;tr[root].r=r;
    if(l==r)
	{
		tr[root].sum=a[rec[l]]; 
		return ;
	}
    int mid=l+r>>1;
    build(root<<1,l,mid);
	build(root<<1|1,mid+1,r);
    push_up(root);
}

void update(int root,int x,int y)
{
    if(tr[root].l==x&&tr[root].r==x)
    {
        tr[root].sum+=y;
        return ;
    }
    int mid=tr[root].l+tr[root].r>>1;
    if(x<=mid) 
	  update(root<<1,x,y);
    if(x>mid) 
	  update(root<<1|1,x,y);
    push_up(root);
}

int querysum(int root,int l,int r)
{
    if(tr[root].l==l&&tr[root].r==r)
      return tr[root].sum;
    int mid=tr[root].l+tr[root].r>>1;
    if(r<=mid) 
	  return querysum(root<<1,l,r);
    if(l>mid) 
	  return querysum(root<<1|1,l,r);
    if(l<=mid&&r>mid)
    {
        int s1=querysum(root<<1,l,mid);
        int s2=querysum(root<<1|1,mid+1,r);
        return s1+s2;
    }
}

int findsum(int x,int y)
{
    int f1=top[x],f2=top[y],ret=0;
    while(f1!=f2)
    {
        if(depth[f1]<depth[f2])
        { 
			swap(f1,f2);
			swap(x,y);
		}
        ret+=querysum(1,dfn[f1],dfn[x]);
        x=fa[f1],f1=top[x];
    }
    if(x==y) 
	  return ret+querysum(1,dfn[x],dfn[y]);
    if(depth[x]>depth[y]) 
	  swap(x,y);
    return ret+querysum(1,dfn[x],dfn[y]);
}

int main()
{
    scanf("%d",&n);
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;i++) 
	  scanf("%d",&a[i]);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs1(1,0);
    dfs2(1,1);
    build(1,1,n);
    scanf("%d",&q);
    while(q--)
    {
        int cz;
        scanf("%d%d%d",&cz,&x,&y);
        if(cz==1)
          update(1,dfn[x],y);
        else
          printf("%d\n",findsum(x,y));
    }
    return 0;
}

 

posted @ 2018-10-07 16:45  Ishtar~  阅读(126)  评论(0编辑  收藏  举报