【SPOJ10628】Count on a tree
阿新 • • 發佈:2019-03-04
using space 每次 graph 一個點 基礎 insert include n+1
題目大意:給定一棵 N 個節點的樹,點有點權,要求回答 M 個詢問,每次詢問點 u 到點 v 的簡單路徑(鏈)上權值第 K 小是多少。
題解:學習到了樹上主席樹。
主席樹維護序列時,每次將後一個點的樹建立在前一個點的樹上,由此構成一個前綴和,並利用可以在線段樹上二分的性質來求 K 小值。樹上主席樹維護的是每個節點到根節點路徑上的前綴和,即:每個點的主席樹建立在其父節點的主席樹基礎上。回答答案時,只需在 u,v,lca(u,v),fa[lca(u,v)] 的四棵主席樹上面二分答案即可。
代碼如下
#include <cstdio> #include <algorithm> using namespace std; const int maxn=1e5+10; int n,m,val[maxn],d[maxn],len; int f[maxn][21],dep[maxn]; struct Graph{ int nxt,to; }e[maxn<<1]; int tot=1,head[maxn]; inline void add_edge(int from,int to){ e[++tot]=(Graph){head[from],to},head[from]=tot; } struct node{ #define ls(x) t[x].lc #define rs(x) t[x].rc int lc,rc,sum; }t[maxn*20]; int cnt,root[maxn]; inline void pushup(int o){t[o].sum=t[ls(o)].sum+t[rs(o)].sum;} int insert(int pre,int l,int r,int pos,int value){ int o=++cnt; t[o]=t[pre]; if(l==r){t[o].sum+=value;return o;} int mid=l+r>>1; if(pos<=mid)ls(o)=insert(ls(pre),l,mid,pos,value); else rs(o)=insert(rs(pre),mid+1,r,pos,value); return pushup(o),o; } int query(int a,int b,int c,int d,int l,int r,int k){ if(l==r)return l; int mid=l+r>>1; int sum=t[ls(c)].sum+t[ls(d)].sum-t[ls(a)].sum-t[ls(b)].sum; if(k<=sum)return query(ls(a),ls(b),ls(c),ls(d),l,mid,k); else return query(rs(a),rs(b),rs(c),rs(d),mid+1,r,k-sum); } inline int ask(int x){return lower_bound(d+1,d+len+1,x)-d;} void read_and_parse(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&val[i]),d[++len]=val[i]; for(int i=1,x,y;i<n;i++){ scanf("%d%d",&x,&y); add_edge(x,y),add_edge(y,x); } sort(d+1,d+len+1); len=unique(d+1,d+len+1)-d-1; } void dfs(int u,int fa){ dep[u]=dep[fa]+1,f[u][0]=fa; for(int i=1;i<=20;i++)f[u][i]=f[f[u][i-1]][i-1]; root[u]=insert(root[fa],1,len,ask(val[u]),1); for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to;if(v==fa)continue; dfs(v,u); } } int lca(int x,int y){ if(dep[x]<dep[y])swap(x,y); for(int i=18;~i;i--)if(dep[f[x][i]]>=dep[y])x=f[x][i]; if(x==y)return x; for(int i=18;~i;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; return f[x][0]; } void solve(){ int lastans=0; dfs(1,0); while(m--){ int x,y,k; scanf("%d%d%d",&x,&y,&k); x=lastans^x; int z=lca(x,y); printf("%d\n",lastans=d[query(root[f[z][0]],root[z],root[x],root[y],1,len,k)]); } } int main(){ read_and_parse(); solve(); return 0; }
【SPOJ10628】Count on a tree