• [bzoj3572] [Hnoi2014]世界树


      十分感人的一道题。。虚树+倍增。。

      想了半天发现我竟然会写?而且似乎想对了。。。。然而细节打挂调了一个下午>_<

      首先把虚树建出来,然后在虚树上跑两遍dfs求出每个点最接近的议事处与距离,再然后计算虚树上每一条边对答案的贡献。。

      令mndis[x]表示点x离最近议事处的距离,mnpos[x]表示点x最近的议事处是哪个。

      对于虚树上每条边i->j(i 是父亲),

      计算贡献时要分两种情况:

      1、mnpos[i]==mnpos[ j ]:这时候,原树上i 到 j 的那条链(不包括i 和j )及其孩子都归mnpos[i]管辖了。

        我们可以先求出i 往 j 那个方向的第一个孩子记为next,

        那么i-> j 这条边对mnpos[i]的贡献就是size[next]-size[ j ]。(size[x]表示原树里x子树里(包括x)点的个数)

      2、mnpos[i]不等于mnpos[ j ]的时候,显然mnpos[i]不在 j 的子树里,而mnpos[ j ]在 j 的子树里。

        现在i-> j 这条边会被分成两部分。。。我们只要找到分界点mid的位置就行了。。

        两个议事处的距离dis等于mndis[i]+mndis[j]+( 边i-> j 的长度 ),

        然后我们就知道mid是mnpos[ j ]往上数多少个祖先。这里似乎只能用倍增求mid= =

        之后的计算就类似情况1了。

      注意:到这时我们只计算了边的贡献,记得最后把没被考虑到的点要加上去;另外这题行末要有空格...吃了一发PE

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<algorithm>
      5 using namespace std;
      6 const int maxn=300023;
      7 const int inf=1000233333;
      8 struct zs{
      9     int too,pre;
     10 }e[maxn<<1];
     11 struct zs1{
     12     int too,pre,dis;
     13 }e1[maxn];
     14 int tot,tot1,last[maxn],last1[maxn];
     15 int size[maxn],dfn[maxn],bel[maxn],fa[maxn],sum[maxn],dep[maxn],next[maxn],tim;
     16 int mndis[maxn],mnpos[maxn],id[maxn],sz[maxn];
     17 int st[maxn],top,poi[maxn],tmp[maxn];
     18 int FA[maxn][20],ans[maxn];
     19 int i,j,k,K,n,m,a;
     20  
     21 int ra;char rx;
     22 inline int read(){
     23     rx=getchar(),ra=0;
     24     while(rx<'0'||rx>'9')rx=getchar();
     25     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
     26 }
     27  
     28  
     29 inline void insert(int a,int b){
     30     e[++tot].too=b,e[tot].pre=last[a],last[a]=tot;
     31     e[++tot].too=a,e[tot].pre=last[b],last[b]=tot;
     32 }
     33 inline void ins(int a,int b){
     34 //  printf("   %d-->%d
    ",a,b);
     35     e1[++tot1].too=b,e1[tot1].dis=dep[b]-dep[a],
     36     e1[tot1].pre=last1[a],last1[a]=tot1;
     37 }
     38  
     39 void dfs(int x){
     40     dep[x]=dep[fa[x]]+1,size[x]=1;
     41     for(int i=1;i<=20&&(1<<i)<dep[x];i++)
     42         FA[x][i]=FA[FA[x][i-1]][i-1];
     43     for(int i=last[x];i;i=e[i].pre)if(e[i].too!=fa[x])
     44         fa[e[i].too]=FA[e[i].too][0]=x,dfs(e[i].too),size[x]+=size[e[i].too];
     45 }
     46 void dfs2(int x,int chain){
     47     int i,mxpos=0;
     48     bel[x]=chain,dfn[x]=++tim;
     49     if(dep[x]>2)sum[x]=sum[fa[x]]+size[fa[x]]-size[x];
     50     for(i=last[x];i;i=e[i].pre)
     51         if(e[i].too!=fa[x]&&size[e[i].too]>=size[mxpos])mxpos=e[i].too;
     52     if(!mxpos)return;
     53     dfs2(mxpos,chain);next[x]=mxpos;
     54     for(i=last[x];i;i=e[i].pre)
     55         if(e[i].too!=fa[x]&&e[i].too!=mxpos)dfs2(e[i].too,e[i].too);
     56 }
     57 inline int getlca(int a,int b){
     58     if(dep[bel[a]]<dep[bel[b]])swap(a,b);
     59     while(bel[a]!=bel[b]){
     60         a=fa[bel[a]];
     61         if(dep[bel[a]]<dep[bel[b]])swap(a,b);
     62     }
     63     return dep[a]<dep[b]?a:b;
     64 }
     65 inline int getnext(int f,int j){//找到f往j方向的第一个孩子 
     66     int pre=0;
     67     while(bel[j]!=bel[f])pre=bel[j],j=fa[bel[j]];
     68     return j==f?pre:next[f];
     69 }
     70 inline int getancestor(int x,int d){//找到x往上d 代祖先 
     71     for(register int i=19;i>=0;i--)
     72         if((1<<i)&d)x=FA[x][i];
     73     return x;
     74 }
     75  
     76 void build(){
     77     int i,lca;
     78     st[top=1]=poi[1];
     79     for(i=2;i<=K;i++){
     80         lca=getlca(poi[i],st[top]);
     81         while(dfn[st[top]]>dfn[lca])
     82             if(dfn[st[--top]]<=dfn[lca]){
     83                 ins(lca,st[top+1]);
     84                 if(lca!=st[top])st[++top]=lca;
     85             }else ins(st[top],st[top+1]);
     86         st[++top]=poi[i];
     87     }
     88     while(top>1)top--,ins(st[top],st[top+1]);
     89 }
     90 void run1(int x){
     91     int tmpmn=id[x]==m?0:inf,tmppos=tmpmn==0?x:inf;
     92     sz[x]=id[x]==m;
     93     for(int i=last1[x];i;i=e1[i].pre){
     94         int to=e1[i].too;
     95         run1(to);sz[x]+=sz[to];
     96         if( (mndis[to]+e1[i].dis<tmpmn)
     97             ||(mndis[to]+e1[i].dis==tmpmn&&mnpos[to]<tmppos) )
     98             tmpmn=mndis[to]+e1[i].dis,tmppos=mnpos[to];
     99     }
    100     mnpos[x]=tmppos,mndis[x]=tmpmn;
    101 }
    102 void run2(int x){
    103     ans[x]=0;
    104     for(int i=last1[x],to=e1[i].too;i;to=e1[i=e1[i].pre].too){
    105         if( (e1[i].dis+mndis[x]<mndis[to])
    106           ||(e1[i].dis+mndis[x]==mndis[to]&&mnpos[x]<mnpos[to]) )
    107           mndis[to]=e1[i].dis+mndis[x],mnpos[to]=mnpos[x];
    108         run2(to);
    109     }
    110 }
    111 void run3(int x){
    112     if(sz[x]==1){ans[x]+=size[x];last1[x]=0;return;}
    113     int i,to,mid,next,j,k=mnpos[x],tmpsize=size[x];
    114      
    115     for(to=e1[i=last1[x]].too;i;to=e1[i=e1[i].pre].too){
    116         run3(to);
    117         next=getnext(x,to),j=mnpos[to],tmpsize-=size[next];
    118         if(j==k)ans[j]+=size[next]-size[to];
    119         else
    120             mid=(mndis[x]+e1[i].dis+mndis[to]),
    121             mid=getancestor(j,(mid>>1)-(!(mid&1)&&k<j)),
    122             ans[j]+=size[mid]-size[to],ans[k]+=size[next]-size[mid];
    123     }
    124     ans[k]+=tmpsize,last1[x]=0;
    125 }
    126  
    127 bool cmp(int a,int b){return dfn[a]<dfn[b];}
    128 int main(){
    129     n=read();
    130     for(i=1;i<n;i++)a=read(),insert(a,read());
    131     dfs(1);dfs2(1,1);
    132     for(m=read();m;m--){
    133         K=read();tot1=0;
    134         for(i=1;i<=K;i++)id[poi[i]=tmp[i]=read()]=m;
    135         sort(poi+1,poi+1+K,cmp),
    136         build(),run1(st[1]),run2(st[1]);
    137         run3(st[1]);ans[mnpos[st[1]]]+=n-size[st[1]];
    138         for(i=1;i<=K;i++)printf("%d ",ans[tmp[i]]);puts("");
    139         if(m>1)for(i=1;i<=K;i++)ans[tmp[i]]=0;
    140     }
    141      
    142     return 0;
    143 }
    View Code

    感人的是我把计算时的东西一次就考虑全了。。。结果多组数据..初始化写残吃了若干发RE..T_T,一开始没发现还写了非递归(反正都把dfn给搞出来了)>_<

    中间手贱还CE了(掀桌。。

    幸好我能用链剖的地方都用了链剖。。。刚好卡在#10.....

  • 相关阅读:
    idea 字体大小设置
    idea单窗口管理多个工程项目
    java迭代器使用(修改元素的值)
    idea自动保存设置+确保修改正确
    服务器暂时无法处理您的请求,请稍后重试。解决方法
    [C#] IpcChannel双向通信,参考MAF的AddInProcess开发插件,服务断开重新打开及服务生存周期管理
    XE10.4.2 IDE关闭LSP
    delphi 色彩搭配,HSV与RGB转换
    金额转大写 (delphi)
    MMDet 踩坑
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/5188065.html
Copyright © 2020-2023  润新知