HNOI2015 接水果
我们考每个盘子对水果的影响。
每个盘子的路径,我们分两种情况讨论
1.a和b不构成祖先关系
那么它能影响的水果必须是起点在a或a的子树,终点在b或b的子树(起终点可调换)
2.a和b构成祖先关系
那么起点必须在b或b的子树,终点在c的子树之外。
我们发现满足要求的起点或终点在dfs序中都是一段连续的区间
我们以起点为x轴,终点为y轴,建一个坐标系,我们发现每个盘子对点的要求都可以用一个矩形来表示,每个查询只是查询一点,查询包含它的权值第k小的矩形
我们可以用经典的扫描线问题来解决。
对于y轴,开一个树状数组套权值线段树,支持区间修改和点查询。
问题解决,时间复杂度O(Nlog2N)
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<cstring> #include<map> using namespace std; map<int,int> H; struct plt{ int x,z,q; }a[40011],ask[40011]; struct rec{ int x,l,r,k,q,id; }d[400011]; struct tree{ int ls,rs,q; }tr[32000001]; int ans[40011],g[40011],next[80011],y[80011],dfn[80011],size[80011]; int fa[40011][16],que[40011],num[40011],root[40011],dep[40011]; int T,tc,tot,ts,t,n,m,q,i,x,z,j,tt; void star(int i,int j) { tt++; next[tt]=g[i]; g[i]=tt; y[tt]=j; } bool cmp(rec a,rec b) { if(a.x==b.x)return a.k<b.k; else return a.x<b.x; } void dfs(int x) { int j,k; size[x]=1; j=g[x]; dfn[x]=++t; while(j!=0){ k=y[j]; if(k!=fa[x][0]){ fa[k][0]=x; dep[k]=dep[x]+1; dfs(k); size[x]+=size[k]; } j=next[j]; } } int jump(int x,int z) { int e; e=0; while(z){ if(z%2==1)x=fa[x][e]; z/=2; e++; } return x; } void newrec(int l,int r,int x,int y,int q) { if(l>r||x>y)return; T++; d[T].x=l;d[T].l=x;d[T].r=y;d[T].k=0;d[T].q=q; T++; d[T].x=r;d[T].l=x;d[T].r=y;d[T].k=2;d[T].q=q; T++; d[T].x=x;d[T].l=l;d[T].r=r;d[T].k=0;d[T].q=q; T++; d[T].x=y;d[T].l=l;d[T].r=r;d[T].k=2;d[T].q=q; } void addrec(int x,int z,int q) { int j,k; if(dep[x]>dep[z])swap(x,z); if(dfn[z]>=dfn[x]&&dfn[z]<dfn[x]+size[x]){ k=jump(z,dep[z]-dep[x]-1); newrec(1,dfn[k]-1,dfn[z],dfn[z]+size[z]-1,q); newrec(dfn[k]+size[k],n,dfn[z],dfn[z]+size[z]-1,q); } else newrec(dfn[x],dfn[x]+size[x]-1,dfn[z],dfn[z]+size[z]-1,q); } int lowbit(int x) { return x&-x; } void Insert(int &t,int l,int r,int x,int y) { if(t==0)t=++tc; if(l==r){ tr[t].q+=y; return; } int mid; mid=(l+r)/2; if(x<=mid)Insert(tr[t].ls,l,mid,x,y); if(x>mid)Insert(tr[t].rs,mid+1,r,x,y); tr[t].q=tr[tr[t].ls].q+tr[tr[t].rs].q; } void Ins(int l,int r,int y,int z) { while(r){ Insert(root[r],1,tot,y,z); r-=lowbit(r); } l--; while(l){ Insert(root[l],1,tot,y,-z); l-=lowbit(l); } } int Find(int l,int r,int k) { if(l==r)return num[l]; int mid,i,chk; chk=0; mid=(l+r)/2; for(i=1;i<=ts;i++)chk+=tr[tr[que[i]].ls].q; if(chk>=k){ for(i=1;i<=ts;i++)que[i]=tr[que[i]].ls; return Find(l,mid,k); } else{ for(i=1;i<=ts;i++)que[i]=tr[que[i]].rs; return Find(mid+1,r,k-chk); } } int Ask(int x,int z) { ts=0; while(x<=n){ que[++ts]=root[x]; x+=lowbit(x); } return Find(1,tot,z); } int main() { scanf("%d%d%d",&n,&m,&q); for(i=1;i<n;i++){ scanf("%d%d",&x,&z); star(x,z); star(z,x); } dfs(1); for(i=1;i<=15;i++) for(j=1;j<=n;j++)fa[j][i]=fa[fa[j][i-1]][i-1]; for(i=1;i<=m;i++){ scanf("%d%d%d",&a[i].x,&a[i].z,&a[i].q); if(!H[a[i].q]){ H[a[i].q]=1; num[++tot]=a[i].q; } } sort(num+1,num+1+tot); for(i=1;i<=tot;i++)H[num[i]]=i; for(i=1;i<=m;i++)a[i].q=H[a[i].q]; for(i=1;i<=m;i++)addrec(a[i].x,a[i].z,a[i].q); for(i=1;i<=q;i++){ scanf("%d%d%d",&ask[i].x,&ask[i].z,&ask[i].q); T++; d[T].x=dfn[ask[i].x];d[T].l=d[T].r=dfn[ask[i].z];d[T].k=1;d[T].id=i;d[T].q=ask[i].q; } sort(d+1,d+1+T,cmp); for(i=1;i<=T;i++){ if(d[i].k==0)Ins(d[i].l,d[i].r,d[i].q,1); if(d[i].k==1)ans[d[i].id]=Ask(d[i].l,d[i].q); if(d[i].k==2)Ins(d[i].l,d[i].r,d[i].q,-1); } for(i=1;i<=q;i++)printf("%d\n",ans[i]); }