BZOJ3653: 谈笑风生
2016-05-29 12:10
330 查看
题目大意:给一棵树,每次询问给定a,k,求三元组(a,b,c)的数量满足:
1.a和b都是c的祖先
2.a和b在树上距离不超过k
3.a,b,c互不相同
显然abc肯定形成竖着的一条链
分两种情况讨论:1.b在a的上方,也就是说对于任意合法的b,c可以在a的子树里随便选,这个方案数是可以直接算出来的
2.b在a下方,这种情况对于不同的b,c只能在b的子树当中选,也就是说此时的方案数总和=∑(siz(b)-1)(deep[b]-deep[a]<=k)
那我们不妨建立一个二维平面,对于树上的每个节点,横坐标为他的dfs序,纵坐标为他的deep值,点权是siz-1
然后问题就变成了求矩形内所有点的和了
这个可以用主席树在线询问,但是我用的离线加树状数组,本来以为能快的,结果忽略了4倍常数QYQ
1.a和b都是c的祖先
2.a和b在树上距离不超过k
3.a,b,c互不相同
显然abc肯定形成竖着的一条链
分两种情况讨论:1.b在a的上方,也就是说对于任意合法的b,c可以在a的子树里随便选,这个方案数是可以直接算出来的
2.b在a下方,这种情况对于不同的b,c只能在b的子树当中选,也就是说此时的方案数总和=∑(siz(b)-1)(deep[b]-deep[a]<=k)
那我们不妨建立一个二维平面,对于树上的每个节点,横坐标为他的dfs序,纵坐标为他的deep值,点权是siz-1
然后问题就变成了求矩形内所有点的和了
这个可以用主席树在线询问,但是我用的离线加树状数组,本来以为能快的,结果忽略了4倍常数QYQ
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 300010 using namespace std; long long to[N<<1],nxt[N<<1],pre ,cnt; void ae(long long ff,long long tt) { cnt++; to[cnt]=tt; nxt[cnt]=pre[ff]; pre[ff]=cnt; } long long fa ,d ,siz ,sit ,cn; void build(long long x) { cn++;sit[x]=cn;siz[x]=1;d[x]=d[fa[x]]+1; long long i,j; for(i=pre[x];i;i=nxt[i]) { j=to[i]; if(j==fa[x]) continue; fa[j]=x; build(j); siz[x]+=siz[j]; } } struct ppp{long long o,x,y,v,num;}b[N*10]; long long ans ; bool cmp(ppp x,ppp y) { if(x.y!=y.y) return x.y<y.y; if(x.x!=y.x) return x.x<y.x; return x.o<y.o; } long long c ; long long n,q; void change(long long x,long long v) { for(;x<=n;x+=x&-x) c[x]+=v; } long long check(long long x) { long long ans=0; for(;x;x-=x&-x) ans+=c[x]; return ans; } int main() { scanf("%lld%lld",&n,&q); long long i,j,x,y; for(i=1;i<n;i++) { scanf("%lld%lld",&x,&y); ae(x,y);ae(y,x); } build(1); for(i=1;i<=q;i++) { scanf("%lld%lld",&x,&y); ans[i]=min(d[x]-1,y)*(siz[x]-1); // cout<<ans[i]; b[(i-1)*4+1]=(ppp){2,sit[x],d[x],1,i}; b[(i-1)*4+2]=(ppp){2,sit[x],d[x]+y,-1,i}; b[(i-1)*4+3]=(ppp){2,sit[x]+siz[x]-1,d[x],-1,i}; b[(i-1)*4+4]=(ppp){2,sit[x]+siz[x]-1,d[x]+y,1,i}; } for(i=1;i<=n;i++) b[4*q+i]=(ppp){1,sit[i],d[i],siz[i]-1,0}; sort(b+1,b+4*q+n+1,cmp); for(i=1;i<=4*q+n;i++) { if(b[i].o==1) change(b[i].x,b[i].v); else ans[b[i].num]+=b[i].v*check(b[i].x); } for(i=1;i<=q;i++) printf("%lld\n",ans[i]); }
相关文章推荐
- Hust oj 1672 玻璃小屋的卫生(枚举)
- JMS消息选择器
- 手机端H5页面-矩形布局
- 前端精选文摘:BFC 神奇背后的原理
- 浏览器内核控制meta name="renderer" 说明文档
- JMS订阅模式消息
- ServletContext对象【持续更新】
- Eclipse如果关闭了JavaScript、xml等文件的校验,我怎么人工去验证某个诸如xml文件格式是否有错误??
- JMS中点对点消息
- 根元素
- 1085: [SCOI2005]骑士精神
- Java二分查找算法
- JMS概述
- 随笔—邀请赛前训—Codeforces Round #327 (Div. 2) Rebranding
- 重建freescale 4.6.2 multilib toolchain
- 抓包来看ftp状态码
- 数据加密(MD5,DES,RSA)简析
- BZOJ3779: 重组病毒
- 【算法笔记】贪心算法——01背包问题
- TI CC2541 OAD流程