(离线树链剖分)HDU - 6162 Ch’s gift
题意:
一颗树,q次查询从u到v路径上所有权值在l到r之间的和。
分析:
一开始想写树上主席树,然后感觉内存不够就放弃。
然后想了一个小时,然后发现,询问似曾相识,回忆起一题。
然后发现直接离线搞就行了。
确切的说这题和HDU4417是完全一样的。
将询问排序,然后把小的点加进去,然后查询。
至于l和r,将两个分开分别处理就行了嘛。
算是比较裸的题了,居然想了这么久。
(哇,后来发现主席树内存是够的。。
可以做,与树链第K大类似,一个数组统计区间内的个数,再开一个longlong保存和即可,
用lca进行二分就行啦。
这样复杂度才nlogn,比树剖快撒。
(哇,比赛的时候同学暴力LCA就A了,而且才700+ms,哇
代码:
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 #include <vector> 6 7 using namespace std; 8 9 const int maxn=100010; 10 11 int n,q,m; 12 13 struct Edge 14 { 15 int to,next; 16 } edge[maxn<<1]; 17 int head[maxn],tot; 18 int top[maxn]; 19 int fa[maxn]; 20 int deep[maxn]; 21 int num[maxn]; 22 int p[maxn]; 23 int fp[maxn]; 24 int son[maxn]; 25 int pos; 26 27 struct P 28 { 29 int val,u; 30 bool operator<(const P a)const 31 { 32 return val<a.val; 33 } 34 }; 35 P val[maxn]; 36 37 38 void addedge(int u,int v) 39 { 40 edge[tot].to = v; 41 edge[tot].next=head[u]; 42 head[u]=tot++; 43 } 44 45 void dfs1(int u,int pre,int d) 46 { 47 deep[u]=d; 48 fa[u]=pre; 49 num[u]=1; 50 for(int i=head[u]; i!=-1; i=edge[i].next) 51 { 52 int v = edge[i].to; 53 if(v!=pre) 54 { 55 dfs1(v,u,d+1); 56 num[u]+=num[v]; 57 if(son[u]==-1||num[v]>num[son[u]])son[u]=v; 58 } 59 } 60 } 61 62 void getpos(int u,int sp) 63 { 64 top[u]=sp; 65 p[u]=pos++; 66 fp[p[u]]=u; 67 if(son[u]==-1)return ; 68 getpos(son[u],sp); 69 for(int i=head[u]; i!=-1; i=edge[i].next) 70 { 71 int v = edge[i].to; 72 if(v!=son[u]&&v!=fa[u])getpos(v,v); 73 } 74 } 75 76 struct Node 77 { 78 int left, right; 79 long long sum; 80 } node[maxn<<2]; 81 82 83 void build(int n,int left,int right) 84 { 85 node[n].left=left,node[n].right=right; 86 node[n].sum=0; 87 if(left==right)return ; 88 int mid = (left+right)>>1; 89 build(n<<1,left,mid); 90 build(n<<1|1,mid+1,right); 91 } 92 93 void push_up(int n) 94 { 95 node[n].sum=node[n<<1].sum+node[n<<1|1].sum; 96 } 97 98 void update(int n,int pos,long long val) 99 { 100 if(node[n].left==node[n].right) 101 { 102 node[n].sum+=val;//wait 103 return ; 104 } 105 int mid = (node[n].left+node[n].right)>>1; 106 if(pos<=mid)update(n<<1,pos,val); 107 else update(n<<1|1,pos,val); 108 push_up(n); 109 } 110 111 long long query(int n,int left,int right) 112 { 113 if(left<=node[n].left&&node[n].right<=right) 114 { 115 return node[n].sum; 116 } 117 int mid = (node[n].left+node[n].right)>>1; 118 long long sum=0; 119 if(mid>=left)sum+=query(n<<1,left,right); 120 if(mid<right)sum+=query(n<<1|1,left,right); 121 return sum; 122 } 123 124 125 long long findSum(int x,int y) 126 { 127 long long tmp = 0; 128 while(top[x]!=top[y]) 129 { 130 if(deep[top[x]]<deep[top[y]])swap(x,y); 131 tmp +=query(1,p[top[x]],p[x]); 132 x=fa[top[x]]; 133 } 134 if(deep[x]>deep[y])swap(x,y); 135 tmp+=query(1,p[x],p[y]); 136 return tmp; 137 } 138 139 struct Q 140 { 141 int u,v,x; 142 int i; 143 }; 144 vector<Q> pl,pr; 145 146 bool cmp(Q a,Q b) 147 { 148 return a.x<b.x; 149 } 150 151 long long ansl[maxn],ansr[maxn]; 152 153 154 void init() 155 { 156 tot=0; 157 memset(head,-1,sizeof(head)); 158 pos=0; 159 memset(son,-1,sizeof(son)); 160 pl.clear(),pr.clear(); 161 } 162 163 164 int main() 165 { 166 while(~scanf("%d%d",&n,&q)) 167 { 168 init(); 169 for(int i=1; i<=n; i++) 170 { 171 scanf("%d",&val[i].val); 172 val[i].u=i; 173 } 174 sort(val+1,val+n+1); 175 for(int i=0; i<n-1; i++) 176 { 177 int u,v; 178 scanf("%d%d",&u,&v); 179 addedge(u,v); 180 addedge(v,u); 181 } 182 dfs1(1,0,0); 183 getpos(1,1); 184 for(int i=0; i<q; i++) 185 { 186 int u,v,a,b; 187 scanf("%d%d%d%d",&u,&v,&a,&b); 188 pl.push_back(Q{u,v,a,i}); 189 pr.push_back(Q{u,v,b,i}); 190 } 191 sort(pl.begin(),pl.end(),cmp); 192 sort(pr.begin(),pr.end(),cmp); 193 int l = 1; 194 build(1,0,pos-1); 195 for(int i=0; i<pl.size(); i++) 196 { 197 while(val[l].val<pl[i].x&&l<=n) 198 { 199 update(1,p[val[l].u],val[l].val); 200 l++; 201 } 202 ansl[pl[i].i]=findSum(pl[i].u,pl[i].v); 203 } 204 build(1,0,pos-1); 205 l=1; 206 for(int i=0; i<pr.size(); i++) 207 { 208 while(val[l].val<=pr[i].x&&l<=n) 209 { 210 update(1,p[val[l].u],val[l].val); 211 l++; 212 } 213 ansr[pr[i].i]=findSum(pr[i].u,pr[i].v); 214 } 215 for(int i=0;i<q-1;i++){ 216 printf("%lld ",ansr[i]-ansl[i]); 217 } 218 printf("%lld\n",ansr[q-1]-ansl[q-1]); 219 } 220 return 0; 221 }