Problem: Query on the tree(二分+划分树)
题目链接:
Problem: Query on the tree
Time limit: 1s Mem limit: 64 MB
Problem Description
There is a tree with n node, labeled from 1 to n, and the root of the tree is 1.
For every node i, if its father is j, its value vi=vj*i%20161119, the value of the root is 1.
Now monster has q queries, for each query, monster give you a node i and a number k (0<=k<20161119),
you should find a node j in i’s subtree to minimize abs(k-vj).
Input
Multiple cases.
In first line there is a number n (n<=1e5), then next n-1 lines, each describes an edge of
the tree.
Next line there is a number q(q<=1e5), then next q lines, each contains two numbers i and k.
Output
Each line output a single number, the minimum number of abs(vj-k).
Sample Input
7 1 2 1 3 2 4 2 5 3 6 3 7 5 1 4 2 7 3 30 6 0 7 7
Sample Output
1 1 9 18 14
题意:给出一棵树和每个节点的点权,现在m个询问,每个询问是问在一个节点的子树上找到一个节点是得那个式子的值最小;
思路:dfs序之后可以得到每个点的子树对应的区间,然后再在这个区间里面找到一个最接近k的节点值,可以二分第x大,然后找到k附近的那一个或者两个数求得答案;
代码:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn=1e5+10; int n,m,first[maxn],last[maxn],cnt; int val[maxn]; vector<int>ve[maxn]; int a[maxn],tree[32][maxn],sorted[maxn],num[32][maxn]; template<class T> void read(T&num) { char CH; bool F=false; for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar()); for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar()); F && (num=-num); } int stk[70], tp; template<class T> inline void print(T p) { if(!p) { puts("0"); return; } while(p) stk[++ tp] = p%10, p/=10; while(tp) putchar(stk[tp--] + '0'); putchar(' '); } void dfs(int cur,int fa) { val[cur]=(int)((LL)val[fa]*cur%20161119); int len=ve[cur].size(); a[++cnt]=(int)val[cur]; first[cur]=cnt; for(int i=0;i<len;i++) { int x=ve[cur][i]; if(x==fa)continue; dfs(x,cur); } last[cur]=cnt; } void build(int dep,int l,int r) { if(l>=r)return ; int mid=(l+r)>>1; int lp=l,rp=mid+1,sum=mid-l+1; for(int i=l;i<=r;i++) { if(tree[dep][i]<sorted[mid])sum--; } for(int i=l;i<=r;i++) { if(i!=l)num[dep][i]=num[dep][i-1]; else num[dep][i]=0; if(tree[dep][i]<sorted[mid]) { tree[dep+1][lp++]=tree[dep][i]; num[dep][i]++; } else if(tree[dep][i]==sorted[mid]&&sum>0) { tree[dep+1][lp++]=tree[dep][i]; num[dep][i]++; sum--; } else { tree[dep+1][rp++]=tree[dep][i]; } } build(dep+1,l,mid), build(dep+1,mid+1,r); } int query(int dep,int l,int r,int ql,int qr,int k) { if(l>=r)return tree[dep][l]; int mid=(l+r)>>1,s,ss; if(l!=ql)s=num[dep][ql-1],ss=num[dep][qr]-num[dep][ql-1]; else s=0,ss=num[dep][qr]; if(k<=ss)return query(dep+1,l,mid,l+s,l+s+ss-1,k); else return query(dep+1,mid+1,r,mid+1+ql-l-s,mid+1+qr-l-s-ss,k-ss); } inline int solve(int L,int R,int k) { int ans=1e9; int l=1,r=R-L+1; while(l<=r) { int mid=(l+r)>>1; if(query(0,1,cnt,L,R,mid)<=k)l=mid+1; else r=mid-1; } int pos=l-1; if(pos) { ans=min(ans,abs(k-query(0,1,cnt,L,R,pos))); if(pos<=R-L)ans=min(ans,abs(k-query(0,1,cnt,L,R,pos+1))); } else ans=min(ans,abs(k-query(0,1,cnt,L,R,pos+1))); return ans; } int main() { while(scanf("%d",&n)!=EOF) { int u,v; cnt=0;val[0]=1; for(int i=0;i<=n;++i) { ve[i].clear(); for(int j=0;j<32;++j) tree[j][i]=num[j][i]=0; } for(int i=1;i<n;++i) { read(u);read(v); ve[u].push_back(v); ve[v].push_back(u); } dfs(1,0); for(int i=1;i<=cnt;++i)sorted[i]=tree[0][i]=a[i]; sort(sorted+1,sorted+cnt+1); build(0,1,cnt); read(m); while(m--) { read(u);read(v); int L=first[u],R=last[u]; print(solve(L,R,v)); } } return 0; }