10628. Count on a treeProblem code: COT |
You are given a tree with N nodes.The tree nodes are numbered from 1 to N.Each node has an integer weight.
We will ask you to perform the following operation:
In the first line there are two integers N and M.(N,M<=100000)
In the second line there are N integers.The ith integer denotes the weight of the ith node.
In the next N-1 lines,each line contains two integers u v,which describes an edge (u,v).
In the next M lines,each line contains three integers u v k,which means an operation asking for the kth minimum weight on the path from node u to node v.
For each operation,print its result.
Input:
8 5
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
2 5 2
2 5 3
2 5 4
7 8 2
Output:
2
8
9
105
7
一天只做了这么一个题,好歹做出来了6666,(其实是照着终于改对了,逃,所以以后还得多做数据结构的题,对于debug能力很有提高,毕竟动辄200行
说题意:真是嗷嗷简单易读的题,树上两点间的所有数找最小值,说思路也是嗷嗷简单,就是在树上建主席树嘛。第一次做树套树的题,被代码量惊呆了,我把一个二分while改成递归还180行呢,上午基本上看懂了邝斌代码的整体思路以及几个函数,本公举今天心情好,把代码按着自己之前用的模板敲了一遍,又试着拼接,现在是真懂了主席树的那些函数以及在线LCA的算法。要不说出来混总是要还的,前几天刷RMQ的时候把LCA的遗留问题给忘了,这次的题明显不应该用离线的,参考了这篇博客:点击打开链接,看懂了代码,自己写的也是用的他的模板,真心挺简单的。
言归正传,主席树是求区间第k小的值,放到这个题里面,除了query函数需要改之外,其他直接照搬,用的还是孙大神的模板,结构体左右结点的写法看起来很清晰,坑也就坑在query函数里面了,其实我最开始就怀疑是不是这里的问题,把所有能打印的数组打出来看了,都没问题,才仔细看了query。公共祖先的Rt是不应该每次递归都求的!说不通了啊
LCA没问题,但是建树的函数需要用心想,以后,也就是这两周,我要努力刷树套树,想是一码事,根本写不出啊!
/********* spoj Count on a tree 2016.1.25 152576 2330ms C++ (g++ 4.9.2) *********/ #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define maxn 200020 ///=============主席树部分开始 struct Node { int ls,rs,cnt; }tr[maxn*40]; int cur,m,n,q,rt[maxn],b[maxn],sortb[maxn]; void tree_init() { cur=0; for(int i=1;i<=n;i++) { scanf("%d",&b[i]); sortb[i]=b[i]; } sort(sortb+1,sortb+1+n); m=1; for(int i=2;i<=n;i++) { if(sortb[i]!=sortb[m]) sortb[++m]=sortb[i]; } } int build(int l,int r) { int k=cur++; if(l==r) { tr[k].cnt=0; return k; } int mid=(l+r)>>1; tr[k].ls=build(l,mid); tr[k].rs=build(mid+1,r); tr[k].cnt=0; return k; } int update(int o,int l,int r,int pos,int val) { int k=cur++; tr[k]=tr[o]; if(l==pos&&r==pos) { tr[k].cnt+=val; return k; } int mid=(l+r)>>1; if(pos<=mid) tr[k].ls=update(tr[o].ls,l,mid,pos,val); else tr[k].rs=update(tr[o].rs,mid+1,r,pos,val); tr[k].cnt=tr[tr[k].ls].cnt+tr[tr[k].rs].cnt; return k; } ///==============主席树部分结束 ///==============在线LCA开始 int dp[maxn*2][25],num; bool vis[maxn]; struct Edge { int u,v,next;///已知的是点权,不是边权! }e[maxn<<1]; int tot,head[maxn]; void lca_init() { tot=0; num=0; memset(head,-1,sizeof(head)); memset(vis,false,sizeof(vis)); } inline void add(int u,int v,int &k) { e[k].u=u;e[k].v=v;e[k].next=head[u];head[u]=k++; e[k].u=v;e[k].v=u;e[k].next=head[v];head[v]=k++; } int ver[maxn*2],R[maxn*2],first[maxn];///节点编号、深度、(前两个下标是遍历次序)点位置 //因为是深搜的序列,欧拉序列长度=2*n-1,我居然才知道! void dfs(int u,int pre,int dep)//不可以用vis数组判环,也可以用pre参数 { ver[++tot]=u; first[u]=tot; R[tot]=dep; for(int k=head[u];k!=-1;k=e[k].next) { int v=e[k].v; if(v==pre) continue; /// dir[v]=dir[u]+w;因为没有边权值,所以深度=距离 dir[]数组没有用 dfs(v,u,dep+1); ver[++tot]=u; R[tot]=dep; } } void ST(int n) { for(int i=1;i<=n;i++) dp[i][0]=i; for(int j=1;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) { // if(i + (1 << (j - 1)) > n) continue; int a=dp[i][j-1],b=dp[i+(1<<(j-1))][j-1]; dp[i][j]=R[a]<R[b]?a:b; } } int RMQ(int l,int r) { int k=0; while((1<<(k+1))<=r-l+1) k++; int a=dp[l][k],b=dp[r-(1<<k)+1][k]; return R[a]<=R[b]?a:b;//? } int LCA(int u,int v) { int x=first[u],y=first[v]; if(x>y) swap(x,y); int res=RMQ(x,y); return ver[res]; } ///=============LCA结束 ///=============综合部分:树套树+查询 void dfs_build(int u,int pre) { int pos=lower_bound(sortb+1,sortb+1+m,b[u])-sortb; rt[u]=update(rt[pre],1,m,pos,1); for(int k=head[u];k!=-1;k=e[k].next) { int v=e[k].v; if(v==pre) continue; dfs_build(v,u); } } int query(int l,int r,int o,int v,int Lca,int k) { /* if(l==r) return l; int mid=(l+r)>>1; int int lca=rt[Lca]; if(k<=tmp) return query(l,mid,tr[o].ls,tr[v].ls,tr[lca].ls,k); else return query(mid+1,r,tr[o].rs,tr[v].rs,tr[lca].rs,k-tmp);*/ int lca_root=rt[Lca]; int pos=lower_bound(sortb+1,sortb+1+m,b[Lca])-sortb; while(l<r) { int mid=(l+r)>>1; int tmp=tr[tr[v].ls].cnt+tr[tr[o].ls].cnt-2*tr[tr[lca_root].ls].cnt+(pos>=l&&pos<=mid); if(tmp>=k) { o=tr[o].ls;v=tr[v].ls;lca_root=tr[lca_root].ls; r=mid; } else { k-=tmp; o=tr[o].rs;v=tr[v].rs;lca_root=tr[lca_root].rs; l=mid+1; } } return l; } ///============综合部分结束 int main() { //freopen("cin.txt","r",stdin); // freopen("out.txt","w",stdout); while(scanf("%d%d",&n,&q)==2) { tree_init(); lca_init(); for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y);//居然是忘了读入数据== add(x,y,num); } dfs(1,1,0);///就当是1是根节点 以谁为根节点建树都一样,树枝都可以掰过去 ST(n*2-1); rt[0]=build(1,m); dfs_build(1,0); int u,v,kth; while(q--) { scanf("%d%d%d",&u,&v,&kth); int tmp=LCA(u,v); //printf("u=%d v=%d lca=%d ",u,v,tmp); printf("%d\n",sortb[query(1,m,rt[u],rt[v],tmp,kth)]); } /* for(int i=1;i<=n;i++) printf("i=%d,rt=%d,first=%d\n",i,rt[i],first[i]); for(int i=1;i<=m;i++) printf("i=%d,sortb=%d\n",i,sortb[i]); for(int i=1;i<=2*n-1;i++) printf("i=%d,ver=%d,R=%d\n",i,ver[i],R[i]); for(int j=1;(1<<j)<=2*n-1;j++) for(int i=1;i+(1<<j)-1<=2*n-1;i++) { // if(i + (1 << (j - 1)) > n) continue; printf("i=%d,j=%d,dp=%d\n",i,j,dp[i][j]); } /* puts("7,4"); printf("%d\n",sortb[query(1,m,rt[7],rt[4],LCA(7,4),1)]); printf("%d\n",sortb[query(1,m,rt[7],rt[4],LCA(7,4),2)]); printf("%d\n",sortb[query(1,m,rt[7],rt[4],LCA(7,4),3)]); printf("%d\n",sortb[query(1,m,rt[7],rt[4],LCA(7,4),4)]); puts("5,8"); printf("%d\n",sortb[query(1,m,rt[5],rt[8],LCA(5,8),1)]); printf("%d\n",sortb[query(1,m,rt[5],rt[8],LCA(5,8),2)]); printf("%d\n",sortb[query(1,m,rt[5],rt[8],LCA(5,8),3)]); printf("%d\n",sortb[query(1,m,rt[5],rt[8],LCA(5,8),4)]); printf("%d\n",sortb[query(1,m,rt[5],rt[8],LCA(5,8),5)]); printf("%d\n",sortb[query(1,m,rt[5],rt[8],LCA(5,8),6)]); puts(""); printf("%d\n",sortb[query(1,m,rt[6],rt[8],LCA(6,8),1)]); printf("%d\n",sortb[query(1,m,rt[6],rt[8],LCA(6,8),2)]); printf("%d\n",sortb[query(1,m,rt[6],rt[8],LCA(6,8),3)]); printf("%d\n",sortb[query(1,m,rt[6],rt[8],LCA(6,8),4)]); printf("%d\n",sortb[query(1,m,rt[6],rt[8],LCA(6,8),5)]); printf("%d\n",sortb[query(1,m,rt[6],rt[8],LCA(6,8),6)]); puts(""); puts("2,8"); printf("%d\n",sortb[query(1,m,rt[2],rt[8],LCA(2,8),1)]); printf("%d\n",sortb[query(1,m,rt[2],rt[8],LCA(2,8),2)]); printf("%d\n",sortb[query(1,m,rt[2],rt[8],LCA(2,8),3)]); printf("%d\n",sortb[query(1,m,rt[2],rt[8],LCA(2,8),4)]); puts("1,8"); printf("%d\n",sortb[query(1,m,rt[1],rt[8],LCA(1,8),1)]); printf("%d\n",sortb[query(1,m,rt[1],rt[8],LCA(1,8),2)]); printf("%d\n",sortb[query(1,m,rt[1],rt[8],LCA(1,8),3)]); puts("");*/ } return 0; }