zoukankan      html  css  js  c++  java
  • 【做题】zoj3649 Social Net——倍增

    这题是吴老师推荐的,于是我就去做了。

    根据题意,在完成最大生成树后,对于树上从x到y的一条路径,求出最大的ck-cj(j<=k,ci为路径上第i个点的权值)。

    我一开始的想法是二分,记路径xy的中点是mid,路径ab的答案记为ans(a,b),最大值为mx(a,b),最小值为mn(a,b),那么,ans(x,y)=max{ans(x,mid),ans(y,mid),mx(mid,y)-mn(x,mid)}。

    但我忘记了一个问题,对于时间复杂度T(n)=2T(n/2)+logn,由主定理可知,解为T(n)=O(n)。换言之这并没有比暴力优越。

    然而,正如同求路径上的最大最小值一样,我们可以通过倍增的方法把ans预处理出来,然后在O(logn)的时间内得到解。

    具体说就是把一个点向上2^i的答案和一个点第2^i-1个祖先到i的答案都预处理出来。而预处理和最终计算答案的方法和上述的二分是完全一致的。

    所以,我们可以通过O(n*logn)的时间完成预处理,再对与每个询问O(logn)地得到解。

    时间复杂度O(n*logn+q*logn)。

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 template <typename tp> inline void read(tp& x)
      4 {
      5     x=0;
      6     char tmp=getchar();bool key=0;
      7     for(;!((tmp>='0'&&tmp<='9')||tmp=='-');) tmp=getchar();
      8     if(tmp=='-') key=1,tmp=getchar();
      9     for(;tmp>='0'&&tmp<='9';) x=(x<<1)+(x<<3)+tmp-'0',tmp=getchar();
     10     if(key) x=-x;
     11 }
     12 const int N=30010,M=50010,MAXPOS=15;
     13 struct edge_for_buildtree{
     14     int a,b,v;
     15     bool operator < (const edge_for_buildtree& x)const
     16     {
     17         return v>x.v;
     18     }
     19 }ed[M];
     20 struct edge_for_lca{
     21     int la,b;
     22 }con[N<<1];
     23 int tot,fir[N];
     24 inline void add(int from,int to)
     25 {
     26     con[++tot].la=fir[from];
     27     con[tot].b=to;
     28     fir[from]=tot;
     29 }
     30 int n,m,q,val[N],flag[N],anc[N][MAXPOS+5],mn[N][MAXPOS+5],mx[N][MAXPOS+5],deep[N];
     31 int recu[N][MAXPOS+5],recd[N][MAXPOS+5];
     32 inline void init()
     33 {
     34     memset(anc,0,sizeof anc);
     35     memset(mn,0x3f,sizeof mn);
     36     memset(mx,0,sizeof mx);
     37     memset(fir,0,sizeof fir);
     38     memset(recu,0,sizeof recu);
     39     memset(recd,0,sizeof recd);
     40     tot=0;
     41 }
     42 int get_flag(int pos)
     43 {
     44     return flag[pos]==pos? pos : flag[pos]=get_flag(flag[pos]);
     45 }
     46 inline void kruskal()
     47 {
     48     int x,y,ans=0,cnt=0;
     49     sort(ed+1,ed+m+1);
     50     for(register int i=1;i<=n;++i) flag[i]=i;
     51     for(register int i=1;i<=m;++i)
     52     {
     53         x=ed[i].a;y=ed[i].b;
     54         x=get_flag(x);y=get_flag(y);
     55         if(x==y) continue;
     56         add(ed[i].a,ed[i].b);
     57         add(ed[i].b,ed[i].a);
     58         ans+=ed[i].v;
     59         flag[x]=y;
     60         if(++cnt==n-1) break;
     61     }
     62     printf("%d
    ",ans);
     63 }
     64 void dfs_init(int pos)
     65 {
     66     deep[pos]=deep[anc[pos][0]]+1;
     67     mn[pos][0]=mx[pos][0]=val[pos];
     68     recu[pos][0]=recd[pos][0]=0;
     69     for(int i=1;i<=MAXPOS;++i)
     70     {
     71         anc[pos][i]=anc[anc[pos][i-1]][i-1];
     72         mn[pos][i]=min(mn[pos][i-1],mn[anc[pos][i-1]][i-1]);
     73         mx[pos][i]=max(mx[pos][i-1],mx[anc[pos][i-1]][i-1]);
     74         recu[pos][i]=max(max(recu[pos][i-1],recu[anc[pos][i-1]][i-1]),mx[anc[pos][i-1]][i-1]-mn[pos][i-1]);
     75         recd[pos][i]=max(max(recd[pos][i-1],recd[anc[pos][i-1]][i-1]),mx[pos][i-1]-mn[anc[pos][i-1]][i-1]);
     76         if(anc[pos][i]==0) break;
     77     }
     78     for(int i=fir[pos];i;i=con[i].la)
     79     {
     80         if(con[i].b==anc[pos][0]) continue;
     81         anc[con[i].b][0]=pos;
     82         dfs_init(con[i].b);
     83     }
     84 }
     85 inline int lca(int x,int y)
     86 {
     87     if(deep[x]<deep[y]) swap(x,y);
     88     for(int i=MAXPOS;i>=0;--i)
     89     {
     90         if(deep[anc[x][i]]>=deep[y]) x=anc[x][i];
     91     }
     92     if(x==y) return x;
     93     for(int i=MAXPOS;i>=0;--i)
     94     {
     95         if(anc[x][i]!=anc[y][i])
     96             x=anc[x][i],y=anc[y][i];
     97     }
     98     return anc[x][0];
     99 }
    100 inline int get_mn(int x,int y)//y is the ancestor of x
    101 {
    102     if(x==y) return val[x];
    103     int res=val[x],len=deep[x]-deep[y]+1;
    104     for(int i=MAXPOS;i>=0;--i)
    105     {
    106         if(len>=(1<<i))
    107             res=min(res,mn[x][i]),x=anc[x][i],len-=(1<<i);
    108     }
    109     return res;
    110 }
    111 inline int get_mx(int x,int y)//y is the ancestor of x
    112 {
    113     if(x==y) return val[x];
    114     int res=val[x],len=deep[x]-deep[y]+1;
    115     for(int i=MAXPOS;i>=0;--i)
    116     {
    117         if(len>=(1<<i))
    118             res=max(res,mx[x][i]),x=anc[x][i],len-=(1<<i);
    119     }
    120     return res;
    121 }
    122 inline int ask_mn(int x,int y,int lc)
    123 {
    124     return min(get_mn(x,lc),get_mn(y,lc));
    125 }
    126 inline int ask_mx(int x,int y,int lc)
    127 {
    128     return max(get_mx(x,lc),get_mx(y,lc));
    129 }
    130 inline int get_recu(int x,int y)//y is the ancestor of x
    131 {
    132     if(x==y) return 0;
    133     int mnpre=1000000,res=0;
    134     for(int i=MAXPOS;i>=0;i--)
    135     {
    136         if(deep[anc[x][i]]>=deep[y])
    137         {
    138             res=max(res,recu[x][i]);
    139             res=max(res,mx[x][i]-mnpre);
    140             mnpre=min(mnpre,mn[x][i]);
    141             x=anc[x][i];
    142         }
    143     }
    144     return res;
    145 }
    146 inline int get_recd(int x,int y)
    147 {
    148     if(x==y) return 0;
    149     int mxpre=0,res=0;
    150     for(int i=MAXPOS;i>=0;i--)
    151     {
    152         if(deep[anc[x][i]]>=deep[y])
    153         {
    154             res=max(res,recd[x][i]);
    155             res=max(res,mxpre-mn[x][i]);
    156             mxpre=max(mxpre,mx[x][i]);
    157             x=anc[x][i];
    158         }
    159     }
    160     return res;
    161 }
    162 inline int solve(int x,int y)
    163 {
    164     if(x==y) return 0;
    165     if(anc[x][0]==y||anc[y][0]==x) return max(0,val[y]-val[x]);
    166     int z=lca(x,y);
    167     int res=max(get_recu(x,z),get_recd(y,z));
    168     res=max(res,ask_mx(y,z,z)-ask_mn(x,z,z));
    169     return res;
    170 }
    171 int main()
    172 {
    173     int x,y,v;
    174     while(scanf("%d",&n)!=EOF)
    175     {
    176         init();
    177         for(register int i=1;i<=n;++i) read(val[i]);
    178         read(m);
    179         for(register int i=1;i<=m;++i)
    180         {
    181             read(x);read(y);read(v);
    182             ed[i]=(edge_for_buildtree){x,y,v};
    183         }
    184         kruskal();
    185         dfs_init(1);
    186         read(q);
    187         for(;q--;)
    188         {
    189             read(x);read(y);
    190             printf("%d
    ",solve(x,y));
    191         }
    192     }
    193     return 0;
    194 }

    小结:通常对于无修改的题目,这种看似无用的二分往往可以通过倍增来优化。

  • 相关阅读:
    结果偏见 (行为经济学)
    天下没有免费的午餐
    双环学习
    信息对称、网络效应
    为什么说盲维是认知升级的重要概念?
    给思维找一个支点
    风险是一种商品
    认知方法论第一课
    A*算法深入
    A*算法入门
  • 原文地址:https://www.cnblogs.com/cly-none/p/7749576.html
Copyright © 2011-2022 走看看