树链剖分 JZOJ 2677. 树A

题目

Description


已知无向连通图GN个点,N-1条边组成。每个点有给定权值。现有M个操作,操作分为2种:操作1,将某点权值更改;操作2,询问从点A至点B路径上所有点的权值和。

 

Input


每个输入文件中仅包含一个测试数据。


第一行包含两个整数N,M


第二行至第N行每行包含2个整数,AB,表示节点A与节点B有一条边相连。


N+1行包含N个整数,表示第N个点的初始权值。


N+2行至第N+M+1行每行包含三个整数,KAB(若K=1,表示将点A权值改为B;若K=2表示询问点A至点B路径上所有点的权值和)




Output


输出文件若干行,分别对应每次操作2的答案。

 

Sample Input

3 2
1 2 
1 3 
1 2 3
2 1 3
2 2 3

Sample Output

4
6
 

Data Constraint

 
 

Hint


对于60%的数据,1<=N,M<=1000


对于100%的数据,2<=N<=30000;0<=M<=200000

 

分析

 

  • 解法一:(我打错了)跑一遍dfs序,将点映射到mapp里
  • 然后用线段树维护值
  • 每一次将值扔到线段树里查找
  • 解法二:树剖模板题

 

代码

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #define ll long long
  5 using namespace std;
  6 int n,m;
  7 int flag[30001],t[30001],h[30001];
  8 int id[30001],fa[30010],son[30001],top[30001],dep[30001];
  9 int mapp[30001],li[30001],siz[30001];
 10 struct sb
 11 {
 12     int l,r;
 13     ll val;
 14 }tr[30001*4];
 15 int cnt=0;
 16 struct node{
 17     int u,v,nx;
 18 }g[300011*2];
 19 void add(int u,int v) { g[++cnt].u=u; g[cnt].v=v; g[cnt].nx=li[u]; li[u]=cnt;
 20 g[++cnt].u=v; g[cnt].v=u; g[cnt].nx=li[v]; li[v]=cnt; }
 21 void dfs1(int u)
 22 {
 23     int mxsiz=0,mxid=0;
 24     siz[u]=1;
 25     for (int i=li[u];i;i=g[i].nx)
 26     {
 27         int v=g[i].v;
 28         if (v!=fa[u])
 29         {
 30             fa[v]=u,dep[v]=dep[u]+1,dfs1(v),siz[u]+=siz[v];
 31             if (siz[v]>mxsiz) mxsiz=siz[v],mxid=v;
 32         }
 33     }
 34     son[u]=mxid;
 35 }
 36 int tot;
 37 void dfs2(int u,int p)
 38 {
 39     top[u]=p,id[u]=++tot;
 40     if(son[u]) dfs2(son[u],p);
 41     for (int i=li[u];i;i=g[i].nx)
 42     {
 43         int v=g[i].v;
 44         if (v!=fa[u]&&v!=son[u])
 45           dfs2(v,v);
 46      } 
 47 }
 48 void build(int k,int a,int b)
 49 {
 50     tr[k].l=a; tr[k].r=b;
 51     if (a==b) return;
 52     int mid=a+b>>1;
 53     build(k<<1,a,mid);
 54     build(k<<1|1,mid+1,b);
 55 }
 56 void ins(int k,int x,int w)
 57 {
 58     if (tr[k].l==tr[k].r&&tr[k].l==x)
 59     {
 60          tr[k].val=w;
 61          return;
 62     }
 63     int mid=(tr[k].l+tr[k].r)>>1;
 64     if (x<=mid) ins(k<<1,x,w);
 65     else ins(k<<1|1,x,w);
 66     tr[k].val=tr[k<<1|1].val+tr[k<<1].val;
 67 }
 68 ll find(int k,int ql, int qr)
 69     {
 70         if (ql<=tr[k].l&&tr[k].r<=qr) return tr[k].val;
 71         int mid=tr[k].l+tr[k].r>>1; ll ret=0;
 72         if (ql<=mid) ret+=find(k<<1,ql,qr);
 73         if (mid+1<=qr) ret+=find(k<<1|1,ql,qr);
 74         return ret;
 75     }
 76 int main ()
 77 {
 78     cin>>n>>m;
 79     for (int i=1,x,y;i<=n-1;i++)
 80     {
 81         scanf("%d %d",&x,&y);
 82         add(x,y);
 83     }
 84     dfs1(1);
 85     dfs2(1,1);
 86     build(1,1,n);
 87     for (int i=1,u;i<=n;i++)
 88       scanf("%d",&u),ins(1,id[i],u);
 89     for (int i=1,k,a,b;i<=m;i++)
 90     {
 91         scanf("%d %d %d",&k,&a,&b);
 92         if (k==1) ins(1,id[a],b);
 93         else
 94         {
 95             ll ans=0;
 96             while (top[a]!=top[b])
 97             {
 98                 if (dep[top[a]]<dep[top[b]]) swap(a,b);
 99                 ans+=find(1,id[top[a]],id[a]);
100                 a=fa[top[a]];
101             }
102             if (dep[a]<dep[b]) swap(a,b);
103             ans+=find(1,id[b],id[a]);
104             printf("%lld\n",ans);
105          } 
106     }
107 }

 

猜你喜欢

转载自www.cnblogs.com/zjzjzj/p/11146411.html