• [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
    ",find(x,k));
    156   }
    157   return 0;
    158 }
  • 相关阅读:
    linux source
    C和指针 第七章 习题
    C和指针 第七章 可变参数
    C和指针 第七章 函数递归与迭代
    C和指针 第五章 位数组
    C和指针 第六章 习题
    Net core学习系列(六)——Net Core路由
    Net core学习系列(五)——Net Core应用程序Startup类介绍
    Net core学习系列(四)——Net Core项目执行流程
    Net core学习系列(三)——Net Core中的依赖注入
  • 原文地址:https://www.cnblogs.com/huangdalaofighting/p/8327422.html
Copyright © 2020-2023  润新知