第九场 hdu 6162 Ch’s gift(树链剖分+线段树)

http://acm.hdu.edu.cn/showproblem.php?pid=6162

 

题目大意:已知树上的每个节点的值和节点之间的关系建成了一棵树,现在查询节点u到节点v的最短路径上的节点值在l到r之间的节点值得和

 

解题思路:套用树链剖分的模板能够得到树上的链并把链上的节点进行了重新的定义(即在同一条链上的节点序列是连续的)。然后对于重新定义的节点进行建树。树有三个关键词,minn,maxx和sum。在查询时对重新定义的节点进行查询(即对u到v所经过的每条链分别进行查询)就能得到查询结果。

 

AC代码:

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <map>
  5 #include <vector>
  6 #include <bits/stdc++.h>
  7 using namespace std;
  8 const int MAXN = 100010;
  9 struct Edge
 10 {
 11     int to,next;
 12 } edge[MAXN*2];
 13 int head[MAXN],tot;
 14 
 15 int top[MAXN];//top[v]表示v所在的重链的顶端节点
 16 int fa[MAXN]; //父亲节点
 17 int deep[MAXN];//深度
 18 int num[MAXN];//num[v]表示以v为根的子树的节点数
 19 int p[MAXN];//p[v]表示v与其父亲节点的连边在线段树中的位置
 20 int fp[MAXN];//和p数组相反
 21 int son[MAXN];//重儿子
 22 int pos;
 23 
 24 
 25 void init()
 26 {
 27     tot = 0;
 28     memset(head,-1,sizeof(head));
 29     pos = 1;//序号其实是从1开始?
 30     memset(son,-1,sizeof(son));
 31 }
 32 void addedge(int u,int v)
 33 {
 34     edge[tot].to = v;
 35     edge[tot].next = head[u];
 36     head[u] = tot++;
 37 }
 38 void dfs1(int u,int pre,int d) //第一遍dfs求出fa,deep,num,son
 39 {
 40     deep[u] = d;
 41     fa[u] = pre;
 42     num[u] = 1;
 43     for(int i = head[u]; i != -1; i = edge[i].next)
 44     {
 45         int v = edge[i].to;
 46         //因为路径是双向的,所以不能等于父及诶单
 47         if(v != pre)
 48         {
 49             //先递归地找到儿子节点的深度,父节点,子节点数目等信息
 50             dfs1(v,u,d+1);
 51             //更新u节点的儿子数目
 52             num[u] += num[v];
 53             if(son[u] == -1 || num[v] > num[son[u]])//求出重儿子
 54                 son[u] = v;
 55         }
 56     }
 57 }
 58 
 59 //因为对于轻儿子来说,top[u]=u,对于重儿子来说,如果son[v]!=-1,那么top[v]=top[son[v]]
 60 void getpos(int u,int sp) //第二遍dfs求出top和p
 61 {
 62     top[u] = sp;
 63     //先找重儿子
 64     if(son[u] != -1)
 65     {
 66         //把边的位置标记一下
 67         p[u] = pos++;
 68         //fp相当于是p的反函数?
 69         fp[p[u]] = u;
 70         //更新重儿子
 71         getpos(son[u],sp);
 72     }
 73     //如果到了叶子节点
 74     else
 75     {
 76         //不再向下dfs
 77         p[u] = pos++;
 78         fp[p[u]] = u;
 79         return;
 80     }
 81     //更新其他的节点
 82     for(int i = head[u] ; i != -1; i = edge[i].next)
 83     {
 84         int v = edge[i].to;
 85         if(v != son[u] && v != fa[u])
 86             getpos(v,v);
 87     }
 88 }
 89 struct node
 90 {
 91     int maxx,minn;
 92     long long sum;
 93 }a[MAXN<<2];
 94 long long  val[MAXN];
 95 int s,t,ut,dt;
 96 int n,m;
 97 void push_up(int k)
 98 {
 99     a[k].minn=min(a[k*2].minn,a[k*2+1].minn);
100     a[k].maxx=max(a[k*2].maxx,a[k*2+1].maxx);
101     a[k].sum=a[k*2].sum+a[k*2+1].sum;
102 }
103 void build(int l,int r,int k)
104 {
105     if(l==r)
106     {
107         a[k].maxx=a[k].minn=a[k].sum=val[fp[l]];
108         return ;
109     }
110     int mid=(l+r)/2;
111     build(l,mid,k*2);
112     build(mid+1,r,k*2+1);
113     push_up(k);
114 }
115 long long query(int L,int R,int l,int r,int k)
116 {
117     int mid=(l+r)/2;
118     if(L<=l&&r<=R)
119     {
120         if(ut<=a[k].minn&&a[k].maxx<=dt)
121         {
122             return a[k].sum;
123         }
124         if(a[k].minn>dt||a[k].maxx<ut)
125         return 0LL;
126         return query(L,R,l,mid,k*2)+query(L,R,mid+1,r,k*2+1);
127     }
128     long long ans=0;
129     if(L<=mid) ans+=query(L,R,l,mid,k*2);
130     if(R>mid) ans+=query(L,R,mid+1,r,k*2+1);
131     return ans;
132 }
133 long long solve(int u,int v)
134 {
135     int f1=top[u];
136     int f2=top[v];
137     long long ans=0;
138     while(f1!=f2)
139     {
140         if(deep[f1]<deep[f2])
141         {
142             swap(f1,f2);
143             swap(u,v);
144         }
145         ans+=query(p[f1],p[u],1,n,1);
146         u=fa[f1];
147         f1=top[u];
148     }
149     if(deep[v]<deep[u])
150     {
151         swap(u,v);
152     }
153     ans+=query(p[u],p[v],1,n,1);
154     return ans;
155 }
156 int main()
157 {
158     while(~scanf("%d%d",&n,&m))
159     {
160         for(int i=1;i<=n;i++)
161         scanf("%lld",&val[i]);
162         int x,y;
163         init();
164         for(int i=1;i<n;i++)
165         {
166             scanf("%d%d",&x,&y);
167             addedge(x,y);
168             addedge(y,x);
169         }
170         dfs1(1,-1,0);
171         getpos(1,1);
172         build(1,n,1);
173 //        for(int i=1;i<=n;i++)
174 //        printf("%d = %d\n",i,fp[i]);
175 
176         for(int i=0;i<m;i++)
177         {
178             scanf("%d%d%d%d",&s,&t,&ut,&dt);
179             val[i]=solve(s,t);
180         }
181         for(int i=0;i<m;i++)
182         {
183             if(i==0)
184             printf("%lld",val[i]);
185             else
186             printf(" %lld",val[i]);
187         }
188         printf("\n");
189     }
190     return 0;
191 }

 

posted @ 2017-08-28 10:43  Wally的博客  阅读(442)  评论(0编辑  收藏  举报