[HZOI 2015]复仇的序幕曲
2018-01-22 08:40
274 查看
【题目描述】
你还梦不梦痛不痛,回忆这么重你怎么背得动 ----序言当年的战火硝烟已经渐渐远去,可仇恨却在阿凯蒂王子的心中越来越深
他的叔父三年前谋权篡位,逼宫杀死了他的父王,用铁血手腕平定了国内所有的不满
只有他一个人孤身逃了出来,而现在他组织了一只强大的军队,反攻的号角已经吹响
大战一触即发,作为他的机智又勇敢的指挥官,你必须要准确及时的完成他布置的任务
这个国家的布局是一棵树,每个城市都是树上的结点,其中每个结点上都有军队ai(人数)
树上的每条边有边权wi,表示通过这条边所需要的时间
当一个城市u受到攻击时,所有城市的军队都会同时向这个城市移动
阿凯蒂王子需要知道在时间T内,u城市最多聚集多少人
【输入格式】
第一行n,m,分别表示城市数目和询问次数第二行有n个正整数,表示每个结点军队人数ai
以下n-1行每行描述树上的一条边的两个端点u,v和边权w
以下m行每行一个询问u,T
表示在时间T内,u城市最多聚集多少人
注意询问之间相互独立
【输出格式】
输出m行,每行一个数表示询问的答案
【样例输入】
5 53 7 1 7 4
2 1 9
3 1 6
4 2 5
5 3 1
5 1
4 3
1 1
1 4
4 2
【样例输出】
57
3
3
7
【提示】
n<=80000,m<=80000边权和军队人数均<=1000
题解:
先简化一下题意,给你一棵树,树上每个点都有一个点权,每次询问和一个点距离小于等于T的所有点的点权和。考虑动态点分,对于每个节点,我们保存两个vector,a[i][0]表示整棵子树到这个点的权值和,a[i][1]表示整棵子树到i的父节点的点权和。
每个vector中保存两个参数,len和x,表示距离小于等于len的点权和是多少。
然后用前缀和统计一下x,每次二分len查询即可。
每次查询一个数容斥一下就好。
//Never forget why you start #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #define inf (2147483647) using namespace std; int n,m,a[100005],lim; struct node{ int next,to,dis; }edge[200005]; int head[100005],size; void putin(int from,int to,int dis){ size++; edge[size].next=head[from]; edge[size].to=to; edge[size].dis=dis; head[from]=size; } int fa[100005][20],dis[100005],depth[100005]; void dfs1(int r,int father){ int i; fa[r][0]=father; depth[r]=depth[father]+1; for(i=head[r];i!=-1;i=edge[i].next){ int y=edge[i].to; if(y!=father){ dis[y]=dis[r]+edge[i].dis; dfs1(y,r); } } } void make(){ lim=log(n)/log(2); for(int i=1;i<=lim;i++) for(int j=1;j<=n;j++) fa[j][i]=fa[fa[j][i-1]][i-1]; } int LCA(int x,int y){ if(depth[x]<depth[y])swap(x,y); for(int i=lim;i>=0;i--) if(depth[fa[x][i]]>=depth[y]) x=fa[x][i]; if(x!=y){ for(int i=lim;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; x=fa[x][0]; y=fa[y][0]; } return x; } int dist(int x,int y){ int lca=LCA(x,y); return dis[x]+dis[y]-dis[lca]*2; } int vis[100005],cnt[100005],d[100005],root,tot,ff[100005]; void getroot(int r,int father){ int i; cnt[r]=1;d[r]=0; for(i=head[r];i!=-1;i=edge[i].next){ int y=edge[i].to; if(!vis[y]&&y!=father){ getroot(y,r); cnt[r]+=cnt[y]; d[r]=max(d[r],cnt[y]); } } d[r]=max(d[r],tot-cnt[r]); if(d[root]>d[r])root=r; } void buildtree(int r,int father){ int i,all=tot; vis[r]=1; ff[r]=father; for(i=head[r];i!=-1;i=edge[i].next){ int y=edge[i].to; if(!vis[y]){ if(cnt[y]>cnt[r])cnt[y]=all-cnt[r];tot=cnt[y]; root=0;getroot(y,r);buildtree(root,r); } } } struct Ans{ int len,x; }; vector<Ans>ans[100005][2]; bool cmp(const Ans a,const Ans b){ return a.len<b.len; } int upper_bound(int x,int y,int k){ int l=0,r=ans[x][y].size()-1,cnt=0; while(l<=r){ int mid=(l+r)>>1; if(ans[x][y][mid].len<=k)cnt=ans[x][y][mid].x,l=mid+1; else r=mid-1; } return cnt; } void insert(int x,int v){ int i; ans[x][0].push_back((Ans){0,v}); for(i=x;ff[i];i=ff[i]){ int len=dist(x,ff[i]); ans[i][1].push_back((Ans){len,v}); ans[ff[i]][0].push_back((Ans){len,v}); } } int find(int x,int k){ int i,ans=upper_bound(x,0,k); for(i=x;ff[i];i=ff[i]){ int len=dist(x,ff[i]); ans-=upper_bound(i,1,k-len); ans+=upper_bound(ff[i],0,k-len); } return ans; } void clean(){ memset(head,-1,sizeof(head)); size=0; } int main(){ freopen("SS.in","r",stdin); freopen("SS.out","w",stdout); int i,j; clean(); scanf("%d%d",&n,&m); for(i=1;i<=n;i++)scanf("%d",&a[i]); for(i=1;i<n;i++){ int u,v,l; scanf("%d%d%d",&u,&v,&l); putin(u,v,l); putin(v,u,l); } dfs1(1,1);make(); tot=n;root=0;d[0]=inf; getroot(1,0);buildtree(root,0); for(i=1;i<=n;i++)insert(i,a[i]); for(i=1;i<=n;i++){ sort(ans[i][0].begin(),ans[i][0].end(),cmp); sort(ans[i][1].begin(),ans[i][1].end(),cmp); } for(i=1;i<=n;i++){ for(j=1;j<ans[i][0].size();j++) ans[i][0][j].x+=ans[i][0][j-1].x; for(j=1;j<ans[i][1].size();j++) ans[i][1][j].x+=ans[i][1][j-1].x; } while(m--){ int x,k; scanf("%d%d",&x,&k); printf("%d\n",find(x,k)); } return 0; }
相关文章推荐
- [COGS 2258][HZOI 2015]复仇的序幕曲
- cogs 2287. [HZOI 2015]疯狂的机器人 (NTT优化DP)
- [COGS2287][HZOI 2015]疯狂的机器人(NTT+组合数学)
- COGS-2282 [HZOI 2015]黑树白(树状数组+树链剖分)
- 「HZOI 2015」Math
- COGS 2580. [HZOI 2015]偏序 II
- [COGS 2287][HZOI 2015]疯狂的机器人
- 【COGS】2287:[HZOI 2015]疯狂的机器人 FFT+卡特兰数+排列组合
- COGS2287 [HZOI 2015]疯狂的机器人
- NKOJ 4028(HZOI 2015)疯狂的机器人(NTT+卡特兰数)
- COGS2580:[HZOI 2015]偏序 II (三层CDQ分治+树状数组)
- COGS 2294. [HZOI 2015] 释迦 (FFT mod any prime)
- [COGS2287][HZOI 2015]疯狂的机器人(NTT)
- [HZOI 2015] Glass Beads
- [COGS2189][HZOI 2015]帕秋莉的超级多项式-NTT-多项式求逆-多项式求ln-多项式开方-多项式求exp-多项式快速幂
- BZOJ 2287. [HZOI 2015]疯狂的机器人 [FFT 组合计数]
- COGS 2123. [HZOI 2015] Glass Beads
- [cogs2314][HZOI 2015] Persistable Editor - 可持久化平衡树
- [任意模数NTT 三模数NTT] COGS 2294 [HZOI 2015] 释迦
- COGS-2258 复仇的序幕曲(动态树分治)