hdu 5692(dfs+线段树) Snacks

题目http://acm.hdu.edu.cn/showproblem.php?pid=5692

题目说每个点至多经过一次,那么就是只能一条路线走到底的意思,看到这题的格式,

多个询问多个更新,

自然而然的就会想到线段树或者树状数组,在建树前先做处理,

用DFS将从起点0出发到任一点的距离求出,

然后将这些节点按照一条一条完整的路线的顺序建到树中,

比如样例是1---2---3         

              |

      6 ---4----5

所以建树的其中一种顺序是1 4 5 6 2 3 。当查询的时候的区间应该是从现在这个点开始到这条路线上的终点,更新的时候也是这个区间更新,相当于把这个区间的所有数都加上一个数,与 poj 3468 类似,lazy操作。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 typedef long long ll;
  8 const int M = 1e5 + 10;
  9 int head[M],cas,num[M],ans,st[M],ed[M];
 10 ll sum[M],a[M];
 11 
 12 ll max(ll x,ll y) {return x>y?x:y;}
 13 
 14 struct Edge{
 15    int to;
 16    int next;
 17 }edge[M*2];
 18 
 19 void add(int x,int y)
 20 {
 21     edge[cas].to=x;
 22     edge[cas].next=head[y];
 23     head[y]=cas++;
 24 }
 25 
 26 void dfs(int x,int y)
 27 {
 28     st[x]=++ans;num[ans]=x;
 29     sum[x]+=sum[y];
 30     for (int i=head[x] ; i!=-1 ; i=edge[i].next)
 31     {
 32         int v=edge[i].to;
 33         if (v==y) continue;
 34         dfs(v,x);
 35     }
 36     ed[x]=ans;
 37 }
 38 struct Tree{
 39     int l,r;
 40     ll ans,mark;
 41 }tree[M*4];
 42 
 43 void down(int i)
 44 {
 45     if(tree[i].mark)
 46     {
 47         tree[i*2].mark+=tree[i].mark;tree[i*2+1].mark+=tree[i].mark;
 48         tree[i*2].ans+=tree[i].mark;tree[i*2+1].ans+=tree[i].mark;
 49         tree[i].mark=0;
 50     }
 51 }
 52 
 53 void build(int i,int left,int right)
 54 {
 55     tree[i].l=left;tree[i].r=right;
 56     tree[i].mark=0;
 57     if (left==right){tree[i].ans=sum[num[left]];return ;}
 58     int mid=(left+right)/2;
 59     build(i*2,left,mid);
 60     build(i*2+1,mid+1,right);
 61     tree[i].ans=max(tree[i*2].ans,tree[i*2+1].ans);
 62 }
 63 
 64 ll findest(int i,int left,int right)
 65 {
 66     if(tree[i].l>=left&&tree[i].r<=right)
 67         return tree[i].ans;
 68     down(i);
 69     int mid=(tree[i].l+tree[i].r)/2;
 70     if(mid>=right){return findest(i*2,left,right);}
 71     else if(mid<left){return findest(i*2+1,left,right);}
 72     else{return max(findest(i*2,left,mid),findest(i*2+1,mid+1,right));}
 73 
 74 }
 75 void update(int i,int left,int right,ll pos)
 76 {
 77     if(tree[i].l>=left&&tree[i].r<=right){tree[i].mark+=pos;tree[i].ans+=pos;return;}
 78     int mid=(tree[i].l+tree[i].r)/2;
 79     down(i);
 80     if(mid<left) update(i*2+1,left,right,pos);
 81     else if(mid>=right) update(i*2,left,right,pos);
 82     else
 83     {
 84         update(i*2,left,mid,pos);
 85         update(i*2+1,mid+1,right,pos);
 86     }
 87     tree[i].ans=max(tree[i*2].ans,tree[i*2+1].ans);
 88 }
 89 
 90 int main()
 91 {
 92     int t,n,m,e=0;
 93     scanf("%d",&t);
 94     while (t--)
 95     {
 96         printf("Case #%d:
",++e);
 97         scanf("%d%d",&n,&m);
 98         memset(head,-1,sizeof(head));
 99         for (int i=1 ; i<n ; i++){
100             int a,b;
101             scanf("%d%d",&a,&b);
102             a++,b++;
103             add(a,b);add(b,a);
104         }
105         cas=0;ans=0;
106         for (int i=1 ; i<=n ; i++) scanf("%I64d",&a[i]),sum[i]=a[i];
107         dfs(1,0);
108         build(1,1,n);
109         while (m--)
110         {
111             int w,b;ll c;
112             scanf("%d",&w);
113             if (w){
114                 scanf("%d",&b);b++;
115                 printf("%I64d
",findest(1,st[b],ed[b]));
116             }
117             else{
118                 scanf("%d%I64d",&b,&c);b++;
119                 ll q=c-a[b];
120                 a[b]=c;
121                 update(1,st[b],ed[b],q);
122             }
123         }
124     }
125     return 0;
126 }
View Code

                                                                                                     

原文地址:https://www.cnblogs.com/JJCHEHEDA/p/5661693.html