• 【BZOJ 3924】[Zjoi2015]幻想乡战略游戏


    题目:

      

    题解:

      对点分树理解加深了233,膜拜zzh干翻紫荆花。

      感谢zzh的讲解。

      首先优化基于传统DP,假设树不发生变化,我们就可以利用DP求出带权重心。

      考虑修改,我们思路不变,还是从root开始找,但发现这样会被卡成$n^2$,原因是每次经过点太多,为了优化,考虑点分树,由于点分树的性质使得假设我们可以在点分树上找到最优解,那么每次最多经过$log$个节点,可以保证时间复杂度。

      然后考虑在点分树转移,假设当前节点为x,我们枚举其在原树中的边,假设当前枚举边的另一端为y,那么由DP可以得出如果以当前边分为两半,若y的一半点权和大于所有点权的一半,那么最优解一定在y那边存在,然后我们由点分树直接跳跃到y对应的块中。若不存在这样的y,则x一定为最优解。

      这样的话我们的目的就是求x点对应的答案以及y一边对应的点权和,我们用三个数组来记录当前x的点分子树的点权和,点分子树到达x的$d*dis$和,以及到达其父亲的$d*dis$和,这样统计x的答案就可以在$log$的时间内完成。

      对于y我们可以开一个$log$大小的数组来记录在点分数上走过的点,并按照原树dfs排序,每次到达一个新的x用$log$更新,并在此序列上维护一个$sum$表示经过路径上x与其儿子s点权和之差,那么考虑若枚举的y是x在原树的儿子或父亲时的情况,分类讨论,利用$sum$快速求出y一边的点权和。

      综上所述,时间复杂度为$O(20nlog_2^nlog_2^{log_2^n})$

    代码:

      1 #define Troy 
      2 #define inf 0x7fffffff
      3 
      4 #include "bits/stdc++.h"
      5 
      6 using namespace std;
      7 
      8 inline int read(){
      9     int s=0,k=1;char ch=getchar();
     10     while (ch<'0'|ch>'9')    ch=='-'?k=-1:0,ch=getchar();
     11     while (ch>47&ch<='9')    s=s*10+(ch^48),ch=getchar();
     12     return s*k;
     13 }
     14 
     15 const int N=1e5+5;
     16 
     17 typedef long long ll;
     18 
     19 struct edges {
     20     int v,nv,w;edges *last;
     21 }edge[N<<1],*head[N];int cnt;
     22 
     23 inline void push(int u,int v,int w){
     24     edge[++cnt]=(edges){v,0,w,head[u]};head[u]=edge+cnt;
     25 }
     26 
     27 int bit[30];
     28 
     29 class ST{
     30 public:
     31     inline void build(int *a,int n){
     32         lgs[0]=-1;
     33         register int i,j;
     34         for (i=1;i<=n;++i)  lgs[i]=lgs[i>>1]+1,f[i][0]=a[i];
     35         for (i=1;bit[i]<=n;++i)
     36             for (j=1;j+bit[i]<=n+1;++j)
     37                 f[j][i]=min(f[j][i-1],f[j+bit[i-1]][i-1]);
     38     }
     39 
     40     inline int query(int l,int r){
     41         if(r<l) swap(l,r);int t=lgs[r-l+1];
     42         return min(f[l][t],f[r-bit[t]+1][t]);
     43     }   
     44 private:
     45     int f[N<<1][20],lgs[N<<1];
     46 }RMQ;
     47 
     48 int dis[N],eular[N<<1],num,beg[N],End[N],n,m;
     49 
     50 inline void DFS(int x,int fa){
     51     eular[beg[x]=++num]=dis[x];
     52     for(edges *i=head[x];i;i=i->last)   if(i->v^fa){
     53         dis[i->v]=dis[x]+i->w;
     54         DFS(i->v,x);
     55         eular[++num]=dis[x];
     56     }End[x]=num;
     57 }
     58 
     59 inline ll get_dis(int x,int y){
     60     return dis[x]+dis[y]-(RMQ.query(beg[x],beg[y])<<1);
     61 }
     62 
     63 class Point_Divide_Tree{
     64 public:
     65     int root,tot,fat[N],size[N],heavy[N],dsum[N];
     66     bool vis[N];
     67     ll dissum[N],fdissum[N];
     68 
     69     inline void dfs(int x,int fa){
     70         size[x]=1,heavy[x]=0;
     71         for(edges *i=head[x];i;i=i->last)   if(i->v!=fa&&!vis[i->v]){
     72             dfs(i->v,x),size[x]+=size[i->v];
     73             heavy[x]=max(heavy[x],size[i->v]);
     74         }heavy[x]=max(heavy[x],tot-size[x]);
     75         if(heavy[root]>heavy[x])    root=x;
     76     }
     77 
     78     inline void build(int x,int fa){
     79         root=0,dfs(x,0);
     80         vis[x=root]=true,fat[x]=fa,dfs(x,x);
     81         for (edges *i=head[x];i;i=i->last) if(!vis[i->v]){
     82             tot=size[i->v];
     83             build(i->v,x),i->nv=root;
     84         }root=x;
     85     }
     86 
     87     inline void insert(int x,int y,int val){
     88         tot+=val;
     89         while(x){
     90             dsum[x]+=val;
     91             dissum[x]+=get_dis(x,y)*val;
     92             if(fat[x]) 
     93                 fdissum[x]+=get_dis(fat[x],y)*val;            
     94             x=fat[x];
     95         }
     96     }
     97 
     98     ll ans,sum[30];
     99     int pos[30],leth;
    100 
    101     inline int calc(int fa,int x,int real){
    102         int ret=dsum[real];
    103         if(dis[x]<dis[fa]){
    104             int l=lower_bound(pos+1,pos+leth+1,beg[fa])-pos,
    105                 r=upper_bound(pos+1,pos+leth+1,End[fa])-pos-1;
    106             ret+=sum[leth]-sum[r]+sum[l-1];
    107         }else{
    108             int l=lower_bound(pos+1,pos+leth+1,beg[x])-pos,
    109                 r=upper_bound(pos+1,pos+leth+1,End[x])-pos-1;
    110             ret+=sum[r]-sum[l-1];
    111         }
    112         return ret;
    113     }
    114 
    115     inline ll calc(int x){        
    116         ll ret=dissum[x];
    117         int p=x;
    118         while(fat[x]){
    119             ret+=(dsum[fat[x]]-dsum[x])*get_dis(fat[x],p)+dissum[fat[x]]-fdissum[x];
    120             x=fat[x];
    121         }return ret;
    122     }
    123 
    124     inline void update(int x,int y){
    125         ll now=dsum[x]-dsum[y];
    126         for(int i=leth+1;i;--i){
    127             sum[i]=sum[i-1]+now;
    128             if(i==1||pos[i-1]<=beg[x]){
    129                 pos[i]=beg[x];
    130                 break;
    131             }else   pos[i]=pos[i-1];
    132         }++leth;
    133     }
    134 
    135     inline void query(int x){
    136         for(edges *i=head[x];i;i=i->last) if(i->nv){
    137             if(calc(x,i->v,i->nv)*2>=tot){
    138                 update(x,i->nv);
    139                 ans=calc(i->nv);               
    140                 query(i->nv);
    141                 break;
    142             }
    143         }
    144     }
    145 
    146     inline void query(){
    147         leth=0;
    148         ans=dissum[root];
    149         query(root);
    150         printf("%lld
    ",ans);
    151     }
    152 }tree;
    153 
    154 int main(){
    155     register int i,j;
    156     for (i=0;i<=20;++i)  bit[i]=1<<i;
    157     n=read(),m=read();
    158     for (i=1;i^n;++i){
    159         int a=read(),b=read(),c=read();
    160         push(a,b,c),push(b,a,c);
    161     }
    162     DFS(1,1),RMQ.build(eular,num);    
    163     tree.tot=n,tree.heavy[0]=inf;
    164     tree.build(1,0),tree.tot=0;
    165     while(m--){
    166         i=read(),j=read();
    167         tree.insert(i,i,j);
    168         tree.query();
    169     }
    170 }
  • 相关阅读:
    Vue中v-for不绑定key会怎样
    关于Vuex可直接修改state问题
    不要完全相信Chrome控制台打印的信息
    Vue挂载元素的替换
    (转)openURL的使用方法
    iOS:将NSDate转换为当前时区时间
    OC中使用 static 、 extern、 const使用
    iOS: 正则表达式
    iOS:原生二维码扫描
    iOS:ABPeoplePickerNavigationController系统通讯录使用
  • 原文地址:https://www.cnblogs.com/Troywar/p/8006813.html
Copyright © 2020-2023  润新知