[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 }

 

posted @ 2018-01-22 08:40  kakakakakaka  阅读(220)  评论(0编辑  收藏  举报

Never forget why you start

//鼠标爆炸特效