数据结构 线段树 hdu 5-8-7-7 Weak Pair 线段树+离散化

来源:互联网 发布:windows phone 同步 编辑:程序博客网 时间:2024/05/17 07:51

题意:T个测试样例,有n个节点,和一个数字K,输入n个数 a1,a2.........an,输入n-1个 u和v ,u是v的祖先,求满足a[ u ] * a[ v ]<=K的个数

思路:首先看到u,v 肯定是要建树的,而且v要与v的所有祖先进行比较,比较的时候,a[ u ]<=K / a[ v ] 满足这个的a[ u ] 都要数进来,所以要进行离散化。

然后建树,先序遍历树,然后用线段树去统计符合的个数,dfs 出来后 要把前面数过之后把分支清掉,重新数


#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;typedef long long ll;const ll maxn=100010;ll k,a[maxn],b[maxn<<1],ans;int n,siz;int sum[maxn<<3];int head[maxn],top;void PushUp(ll rt){sum[rt]=sum[rt<<1] + sum[rt<<1|1];}void build(ll l,ll r,ll rt){if(l==r){sum[rt]=0;return ;}int m=(l+r)>>1;build(lson);build(rson);PushUp(rt);}void update(ll p,ll ss,ll l,ll r,ll rt){//p要改的位置,ss为数值if(l==r){sum[rt]+=ss;return ;} int m=(l+r)>>1;if(p<=m) update(p,ss,lson);else update(p,ss,rson);PushUp(rt);}ll query(ll L,ll R,ll l,ll r,ll rt){//询问L,R之间if(L<=l && r<=R){return sum[rt];}int m=(l+r)>>1;int ret=0;if(L<=m) ret+=query(L,R,lson);if(R>m) ret+=query(L,R,rson);return ret;}//-------------------------struct Edge{int to,from;}edge[maxn<<1];void into(){memset(head,-1,sizeof(head));memset(sum,0,sizeof(sum));top=0;ans=0;}void add(int u,int v){edge[top].to=v;edge[top].from=head[u];head[u]=top++;}void dfs(int root){int l=lower_bound(b+1,b+siz+1,k/a[root])-b;ans+= query(1,l,1,siz,1);int pos=lower_bound(b+1,b+siz+1,a[root])-b;update(pos,1,1,siz,1);for(int i=head[root];i!=-1;i=edge[i].from){int son=edge[i].to;dfs(son);}update(pos,-1,1,siz,1);}int main(){int T;int cas=1;scanf("%d",&T);while(T--){scanf("%d%I64d",&n,&k);into();int cnt=1;int root=0;for(int i=1;i<=n;i++){scanf("%I64d",&a[i]);b[cnt++]=a[i];}for(int i=1;i<=n;i++)b[cnt++]=k/a[i];//离散化 sort(b+1,b+cnt);siz=unique(b+1,b+cnt)-(b+1);build(1,siz,1);int u,v;for(int i=1;i<n;i++){scanf("%d%d",&u,&v);add(u,v);if(i==1) root=u;if(root==v) root=u;}dfs(root);printf("%I64d\n",ans);}return 0;}


0 0