[HZOI 2015]复仇的序幕曲
【题目描述】
你还梦不梦痛不痛,回忆这么重你怎么背得动 ----序言
当年的战火硝烟已经渐渐远去,可仇恨却在阿凯蒂王子的心中越来越深
他的叔父三年前谋权篡位,逼宫杀死了他的父王,用铁血手腕平定了国内所有的不满
只有他一个人孤身逃了出来,而现在他组织了一只强大的军队,反攻的号角已经吹响
大战一触即发,作为他的机智又勇敢的指挥官,你必须要准确及时的完成他布置的任务
这个国家的布局是一棵树,每个城市都是树上的结点,其中每个结点上都有军队ai(人数)
树上的每条边有边权wi,表示通过这条边所需要的时间
当一个城市u受到攻击时,所有城市的军队都会同时向这个城市移动
阿凯蒂王子需要知道在时间T内,u城市最多聚集多少人
【输入格式】
第一行n,m,分别表示城市数目和询问次数
第二行有n个正整数,表示每个结点军队人数ai
以下n-1行每行描述树上的一条边的两个端点u,v和边权w
以下m行每行一个询问u,T
表示在时间T内,u城市最多聚集多少人
注意询问之间相互独立
【输出格式】
输出m行,每行一个数
表示询问的答案
【样例输入】
5 5
3 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
【样例输出】
5
7
3
3
7
【提示】
n<=80000,m<=80000
边权和军队人数均<=1000
题解:
先简化一下题意,给你一棵树,树上每个点都有一个点权,每次询问和一个点距离小于等于T的所有点的点权和。
考虑动态点分,对于每个节点,我们保存两个vector,a[i][0]表示整棵子树到这个点的权值和,a[i][1]表示整棵子树到i的父节点的点权和。
每个vector中保存两个参数,len和x,表示距离小于等于len的点权和是多少。
然后用前缀和统计一下x,每次二分len查询即可。
每次查询一个数容斥一下就好。
1 //Never forget why you start 2 #include<iostream> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<cmath> 7 #include<algorithm> 8 #include<vector> 9 #define inf (2147483647) 10 using namespace std; 11 int n,m,a[100005],lim; 12 struct node{ 13 int next,to,dis; 14 }edge[200005]; 15 int head[100005],size; 16 void putin(int from,int to,int dis){ 17 size++; 18 edge[size].next=head[from]; 19 edge[size].to=to; 20 edge[size].dis=dis; 21 head[from]=size; 22 } 23 int fa[100005][20],dis[100005],depth[100005]; 24 void dfs1(int r,int father){ 25 int i; 26 fa[r][0]=father; 27 depth[r]=depth[father]+1; 28 for(i=head[r];i!=-1;i=edge[i].next){ 29 int y=edge[i].to; 30 if(y!=father){ 31 dis[y]=dis[r]+edge[i].dis; 32 dfs1(y,r); 33 } 34 } 35 } 36 void make(){ 37 lim=log(n)/log(2); 38 for(int i=1;i<=lim;i++) 39 for(int j=1;j<=n;j++) 40 fa[j][i]=fa[fa[j][i-1]][i-1]; 41 } 42 int LCA(int x,int y){ 43 if(depth[x]<depth[y])swap(x,y); 44 for(int i=lim;i>=0;i--) 45 if(depth[fa[x][i]]>=depth[y]) 46 x=fa[x][i]; 47 if(x!=y){ 48 for(int i=lim;i>=0;i--) 49 if(fa[x][i]!=fa[y][i]) 50 x=fa[x][i],y=fa[y][i]; 51 x=fa[x][0]; 52 y=fa[y][0]; 53 } 54 return x; 55 } 56 int dist(int x,int y){ 57 int lca=LCA(x,y); 58 return dis[x]+dis[y]-dis[lca]*2; 59 } 60 int vis[100005],cnt[100005],d[100005],root,tot,ff[100005]; 61 void getroot(int r,int father){ 62 int i; 63 cnt[r]=1;d[r]=0; 64 for(i=head[r];i!=-1;i=edge[i].next){ 65 int y=edge[i].to; 66 if(!vis[y]&&y!=father){ 67 getroot(y,r); 68 cnt[r]+=cnt[y]; 69 d[r]=max(d[r],cnt[y]); 70 } 71 } 72 d[r]=max(d[r],tot-cnt[r]); 73 if(d[root]>d[r])root=r; 74 } 75 void buildtree(int r,int father){ 76 int i,all=tot; 77 vis[r]=1; 78 ff[r]=father; 79 for(i=head[r];i!=-1;i=edge[i].next){ 80 int y=edge[i].to; 81 if(!vis[y]){ 82 if(cnt[y]>cnt[r])cnt[y]=all-cnt[r];tot=cnt[y]; 83 root=0;getroot(y,r);buildtree(root,r); 84 } 85 } 86 } 87 struct Ans{ 88 int len,x; 89 }; 90 vector<Ans>ans[100005][2]; 91 bool cmp(const Ans a,const Ans b){ 92 return a.len<b.len; 93 } 94 int upper_bound(int x,int y,int k){ 95 int l=0,r=ans[x][y].size()-1,cnt=0; 96 while(l<=r){ 97 int mid=(l+r)>>1; 98 if(ans[x][y][mid].len<=k)cnt=ans[x][y][mid].x,l=mid+1; 99 else r=mid-1; 100 } 101 return cnt; 102 } 103 void insert(int x,int v){ 104 int i; 105 ans[x][0].push_back((Ans){0,v}); 106 for(i=x;ff[i];i=ff[i]){ 107 int len=dist(x,ff[i]); 108 ans[i][1].push_back((Ans){len,v}); 109 ans[ff[i]][0].push_back((Ans){len,v}); 110 } 111 } 112 int find(int x,int k){ 113 int i,ans=upper_bound(x,0,k); 114 for(i=x;ff[i];i=ff[i]){ 115 int len=dist(x,ff[i]); 116 ans-=upper_bound(i,1,k-len); 117 ans+=upper_bound(ff[i],0,k-len); 118 } 119 return ans; 120 } 121 void clean(){ 122 memset(head,-1,sizeof(head)); 123 size=0; 124 } 125 int main(){ 126 freopen("SS.in","r",stdin); 127 freopen("SS.out","w",stdout); 128 int i,j; 129 clean(); 130 scanf("%d%d",&n,&m); 131 for(i=1;i<=n;i++)scanf("%d",&a[i]); 132 for(i=1;i<n;i++){ 133 int u,v,l; 134 scanf("%d%d%d",&u,&v,&l); 135 putin(u,v,l); 136 putin(v,u,l); 137 } 138 dfs1(1,1);make(); 139 tot=n;root=0;d[0]=inf; 140 getroot(1,0);buildtree(root,0); 141 for(i=1;i<=n;i++)insert(i,a[i]); 142 for(i=1;i<=n;i++){ 143 sort(ans[i][0].begin(),ans[i][0].end(),cmp); 144 sort(ans[i][1].begin(),ans[i][1].end(),cmp); 145 } 146 for(i=1;i<=n;i++){ 147 for(j=1;j<ans[i][0].size();j++) 148 ans[i][0][j].x+=ans[i][0][j-1].x; 149 for(j=1;j<ans[i][1].size();j++) 150 ans[i][1][j].x+=ans[i][1][j-1].x; 151 } 152 while(m--){ 153 int x,k; 154 scanf("%d%d",&x,&k); 155 printf("%d\n",find(x,k)); 156 } 157 return 0; 158 }