• [ZJOI2015] 幻想乡战略游戏


    题解:

    个人认为这道题很不友好,因为思路不清晰调了好久。

    这道题实际上就是求一棵树的带权重心,很显然一个点越远离带权重心,权值和就会越大。

    那么我们先说一下暴力的思路,假设当前点为x,如果存在一个点y,权值和小于x,那么就向y这个方向转移,直到与x相邻的点中没有权值和比x小的,那么此时的x就是答案。

    这种做法是$O(n^{2})$的,显然过不了所有的数据,考虑优化。

    考虑动态点分,假设我们每次都从根节点x来搜索答案,那么如果当前点不是答案,那么与当前点相邻的点中,一定存在答案比当前点小的点y,而且这个点若存在就是唯一存在。

    那么我们找到y所在子树的重心z,继续从z开始做就好。

    由于点分树的深度最深为logn,所以这种算法有复杂度保证。

    注意:这道题普通的RMQ求LCA过不了,会超时,要用查询复杂度为$O(1)$的欧拉序LCA。

      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 #define inf (2147483647)
      9 using namespace std;
     10 typedef long long lol;
     11 int n,m,lim;
     12 struct node{
     13   int next,to;
     14   lol dis;
     15 }edge[200005];
     16 int head[100005],size;
     17 void putin(int from,int to,lol dis){
     18   size++;
     19   edge[size].next=head[from];
     20   edge[size].to=to;
     21   edge[size].dis=dis;
     22   head[from]=size;
     23 }
     24 int place[100005],dfscnt,st[200005][21],dfn,o[100005];
     25 lol dis[100005];
     26 void dfs1(int r,int father){
     27   int i,s=++dfn;
     28   st[++dfscnt][0]=s;
     29   o[s]=r;
     30   place[r]=dfscnt;
     31   for(i=head[r];i!=-1;i=edge[i].next){
     32     int y=edge[i].to;
     33     if(y!=father){
     34       dis[y]=dis[r]+edge[i].dis;
     35       dfs1(y,r);
     36       st[++dfscnt][0]=s;
     37     }
     38   }
     39 }
     40 void make(){
     41   lim=log(n*2)/log(2);
     42   for(int i=1;i<=lim;i++)
     43     for(int j=1;j<=dfscnt;j++)
     44       if(j+(1<<i)-1<=dfscnt)
     45     st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
     46 }
     47 int LCA(int x,int y){
     48   if(place[x]>place[y])swap(x,y);
     49   int lg=log(place[y]-place[x]+1)/log(2);
     50   return o[min(st[place[x]][lg],st[place[y]-(1<<lg)+1][lg])];
     51 }
     52 lol dist(int x,int y){
     53   int lca=LCA(x,y);
     54   return dis[x]+dis[y]-dis[lca]*2;
     55 }
     56 int vis[100005],cnt[100005],d[100005],tot,root,ff[100005];
     57 void getroot(int r,int father){
     58   int i;
     59   cnt[r]=1;d[r]=0;
     60   for(i=head[r];i!=-1;i=edge[i].next){
     61     int y=edge[i].to;
     62     if(!vis[y]&&y!=father){
     63       getroot(y,r);
     64       cnt[r]+=cnt[y];
     65       d[r]=max(d[r],cnt[y]);    
     66     }
     67   }
     68   d[r]=max(d[r],tot-cnt[r]);
     69   if(d[root]>d[r])root=r;
     70 }
     71 void buildtree(int r,int father){
     72   int i,all=tot;
     73   vis[r]=1;ff[r]=father;
     74   for(i=head[r];i!=-1;i=edge[i].next){
     75     int y=edge[i].to;
     76     if(!vis[y]){
     77       if(cnt[y]>cnt[r])cnt[y]=all-cnt[r];tot=cnt[y];
     78       root=0;getroot(y,r);buildtree(root,r);
     79     }
     80   }
     81 }
     82 lol p[100005][2];
     83 void insert(int x,int v){
     84   int i;
     85   for(i=x;ff[i];i=ff[i]){
     86     lol len=dist(x,ff[i]);
     87     p[i][1]+=len*v;
     88     p[ff[i]][0]+=len*v;
     89   }
     90   for(i=x;i;i=ff[i])cnt[i]+=v;
     91 }
     92 lol query(int x){
     93   int i;
     94   lol ans=p[x][0];
     95   for(i=x;ff[i];i=ff[i]){
     96     lol len=dist(x,ff[i]);
     97     ans+=p[ff[i]][0];
     98     ans+=len*(cnt[ff[i]]-cnt[i]);
     99     ans-=p[i][1];
    100   }
    101   return ans;
    102 }
    103 lol find(int r,lol ans){
    104   int i,to=0;
    105   vis[r]=1;
    106   for(i=head[r];i!=-1;i=edge[i].next){
    107     int y=edge[i].to;
    108     lol tmp=query(y);
    109     if(tmp<ans){to=y;break;}
    110   }
    111   if(to){
    112     for(i=to;ff[i]!=r;i=ff[i]);
    113     ans=query(i);
    114     ans=find(i,ans);
    115     return ans;
    116   }
    117   else return ans;
    118 }
    119 void clean(){
    120   memset(head,-1,sizeof(head));
    121   size=0;    
    122 }
    123 int read(){
    124   int ans=0,f=1;char i=getchar();
    125   while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();}
    126   while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();}
    127   return ans*f;
    128 }
    129 int main(){
    130   freopen("zjoi15_tree.in","r",stdin);
    131   freopen("zjoi15_tree.out","w",stdout);
    132   clean();
    133   int i,j;
    134   n=read();m=read();
    135   for(i=1;i<n;i++){
    136     int u,v;lol l;
    137     u=read();v=read();l=read();
    138     putin(u,v,l);
    139     putin(v,u,l);    
    140   }
    141   dfs1(1,0);make();
    142   tot=n;root=0;d[0]=inf;
    143   getroot(1,0);buildtree(root,0);
    144   for(i=1;i<=n;i++)if(!ff[i]){root=i;break;}
    145   memset(cnt,0,sizeof(cnt));
    146   while(m--){
    147     int x,v;
    148     x=read();v=read();
    149     insert(x,v);
    150     printf("%lld
    ",find(root,p[root][0]));    
    151   }
    152   return 0;    
    153 }
  • 相关阅读:
    学习进度7
    《机器学习十讲》学习报告六
    《机器学习十讲》学习报告五
    《机器学习十讲》学习报告四
    《机器学习十讲》学习报告三
    华为机试题 仿苹果
    C++ STL 六大组件的交互关系
    C++ STL 源码 阅读
    抽象类和接口的区别
    重载 & 重写 在java 中
  • 原文地址:https://www.cnblogs.com/huangdalaofighting/p/8327468.html
Copyright © 2020-2023  润新知