hdu 4605 线段树与二叉树遍历
思路:
首先将所有的查询有一个vector保存起来。我们从1号点开始dfs这颗二叉树,用线段树记录到当前节点时,走左节点的有多少比要查询该节点的X值小的,有多少大的,
同样要记录走右节点的有多少比X小的,多少比X大的。小和大的x,y值题目给了。当要进行左儿子时,建该节点值插入走左的线段树,回退的时候将其删除,进入右儿子时将其插入走右的线段树,同样回退时删除。遍历完一个树,整个查询就做完了,最后输出。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #define Maxn 200100 #define lson(x) (x<<1) #define rson(x) ((x<<1)+1) #define mid ((tree[po].l+tree[po].r)>>1) #define inf 100000000 using namespace std; struct Query{ int x,i; }; struct AA{ int x,y; }ans[Maxn]; struct Tree{ int l,r,lnum,rnum; }tree[Maxn*20]; int head[Maxn],e,w[Maxn],Index[Maxn],flag=0,L,R,Lsum,Rsum; vector<Query> query[Maxn]; struct Edge{ int u,v,next; }edge[Maxn]; void buildTree(int l,int r,int po) { tree[po].l=l,tree[po].r=r; tree[po].lnum=0,tree[po].rnum=0; if(l==r) return ; buildTree(l,mid,lson(po)); buildTree(mid+1,r,rson(po)); } void Insert(int val,int po,int type) { if(tree[po].l==tree[po].r) { if(type) tree[po].rnum++; else tree[po].lnum++; return ; } if(type) tree[po].rnum++; else tree[po].lnum++; if(Index[mid]>=val) Insert(val,lson(po),type); else Insert(val,rson(po),type); } void del(int val,int po,int type) { if(tree[po].l==tree[po].r) { if(type) tree[po].rnum--; else tree[po].lnum--; return ; } if(type) tree[po].rnum--; else tree[po].lnum--; if(Index[mid]>=val) del(val,lson(po),type); else del(val,rson(po),type); } void get_Num(int val,int po) { if(Index[tree[po].l]>val) return ; if(Index[tree[po].r]<val) { R+=tree[po].rnum; L+=tree[po].lnum; return ; } if(tree[po].l==tree[po].r) { if(tree[po].rnum||tree[po].lnum)//如果图中有相同数值,则不能到达 flag=1; return ; } get_Num(val,lson(po)); get_Num(val,rson(po)); } void init() { e=0; Lsum=Rsum=0; memset(head,-1,sizeof(head)); for(int i=0;i<=110010;i++) { query[i].clear(); ans[i].x=ans[i].y=0; } } void add(int u,int v) { edge[e].u=u;edge[e].v=v;edge[e].next=head[u];head[u]=e++; } void dfs(int u)//进行二叉树遍历 { int i,j,temp,Size,pos; Size=query[u].size(); for(i=0;i<Size;i++) { L=R=flag=0; get_Num(query[u][i].x,1); if(flag) { ans[query[u][i].i].y=-1; continue; } ans[query[u][i].i].y+=L*3; ans[query[u][i].i].y+=Lsum-L; ans[query[u][i].i].y+=R*3; ans[query[u][i].i].y+=Rsum-R; ans[query[u][i].i].x+=R; } int f=0; for(i=head[u];i!=-1;i=edge[i].next) { if(f) { Insert(w[u],1,1); Rsum++; } else { Insert(w[u],1,0); Lsum++; } f++; dfs(edge[i].v); if(f==2) { del(w[u],1,1); Rsum--; } else { del(w[u],1,0); Lsum--; } } } int main() { int n,m,q,t,i,j,a,b,u,num; scanf("%d",&t); while(t--) { init(); num=0; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",w+i); Index[i]=w[i]; } sort(Index+1,Index+n+1); num=1; for(i=2;i<=n;i++)//将坐标离散化 if(Index[i]>Index[num]) Index[++num]=Index[i]; buildTree(1,num,1);//建立线段树 scanf("%d",&m); for(i=1;i<=m;i++) { scanf("%d%d%d",&u,&a,&b); add(u,b); add(u,a); } scanf("%d",&q); Query temp; int v; for(i=1;i<=q;i++)//将所有查询保存起来 { scanf("%d%d",&v,&temp.x); temp.i=i; query[v].push_back(temp); } int f=0;//标记走左还是右 for(i=head[1];i!=-1;i=edge[i].next)//从1号节点开始遍历 { if(f)//若走右 { Insert(w[1],1,1);//将该值插入右线段树,并且总数加1 Rsum++; } else { Insert(w[1],1,0);//插入左线段树,总数加1 Lsum++; } f++; dfs(edge[i].v); if(f==2) { del(w[1],1,1);//从右儿子退出,将其删除,总数减1 Rsum--; } else { del(w[1],1,0);//从左儿子退出 Lsum--; } } for(i=1;i<=q;i++) { if(ans[i].y!=-1) printf("%d %d\n",ans[i].x,ans[i].y); else printf("0\n"); } } return 0; }