• luogu3233 世界树 (虚树)


    反正肯定要建虚树,考虑建完之后怎么做

    先随便dp一下算出来距离某点最近的询问点mi[x](因为有的虚树上的点它不是询问点嘛)

    那我们对于某条链x到fa[x]上的非虚树上的点(包括他们的非虚树上的孩子),要么把它分给mi[x],要么分给mi[fa[x]]

    我找到这个中间点以后,在原树上倍增跳过去,算他的size

    这个分法是以$frac{len[mi[x]]+len[x]+len[mi[fa[x]]]}{2}$再加加减减一些细节决定的(len[x]表示x到fa[x]的链的长度)

    除此之外,每个在虚树上的点x(以及它不在虚树上的孩子),都归属于mi[x]

      1 #include<bits/stdc++.h>
      2 #define mp make_pair
      3 #define CLR(a,x) memset(a,x,sizeof(a))
      4 using namespace std;
      5 typedef long long ll;
      6 typedef unsigned long long ull;
      7 typedef pair<int,int> pa;
      8 const int maxn=3e5+10,inf=1e9;
      9 
     10 inline ll rd(){
     11     ll x=0;char c=getchar();int neg=1;
     12     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
     13     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
     14     return x*neg;
     15 }
     16 
     17 int N,Q;
     18 int eg[maxn*2][2],egh[maxn],ect;
     19 int fa[maxn][22],dep[maxn],dfn[maxn],tot,siz[maxn];
     20 
     21 inline void adeg(int a,int b){
     22     eg[++ect][0]=b,eg[ect][1]=egh[a],egh[a]=ect;
     23 }
     24 
     25 inline void dfs1(int x){
     26     dfn[x]=++tot;
     27     for(int i=0;fa[x][i]&&fa[fa[x][i]][i];i++){
     28         fa[x][i+1]=fa[fa[x][i]][i];
     29     }
     30     siz[x]=1;
     31     for(int i=egh[x];i;i=eg[i][1]){
     32         int b=eg[i][0];if(b==fa[x][0]) continue;
     33         fa[b][0]=x,dep[b]=dep[x]+1;
     34         dfs1(b);siz[x]+=siz[b];
     35     }
     36 }
     37 
     38 inline int jump(int x,int d){
     39     int i=0;
     40     while(d){
     41         if(d&1) x=fa[x][i];
     42         i++,d>>=1;
     43     }return x;
     44 }
     45 
     46 inline int getlca(int x,int y){
     47     if(dep[x]<dep[y]) swap(x,y);
     48     for(int i=log2(dep[x]-dep[y]);i>=0&&dep[x]!=dep[y];i--){
     49         if(dep[fa[x][i]]>=dep[y])
     50             x=fa[x][i];
     51     }
     52     if(x==y) return x;
     53     for(int i=log2(dep[x]);i>=0;i--){
     54         if(fa[x][i]!=fa[y][i]) 
     55             x=fa[x][i],y=fa[y][i];
     56     }
     57     return fa[x][0];
     58 }
     59 
     60 inline bool cmp(int x,int y){return dfn[x]<dfn[y];}
     61 
     62 int xfa[maxn],xsh[maxn],xbr[maxn];
     63 
     64 int h[maxn],stk[maxn],hd,len[maxn];
     65 int ans[maxn],id[maxn],pct;
     66 bool rea[maxn];
     67 inline void connect(int x,int y){
     68     // printf("		connect:%d %d
    ",x,y);
     69     xfa[x]=y,xbr[x]=xsh[y],xsh[y]=x,len[x]=dep[x]-dep[y];
     70 }
     71 inline void build(int m){
     72     sort(h+1,h+m+1,cmp);
     73     stk[hd=1]=1;id[++pct]=1;
     74     for(int i=1;i<=m;i++){
     75         rea[h[i]]=1;id[++pct]=h[i];
     76         int lca=getlca(stk[hd],h[i]);
     77         int lst=0;
     78         while(dfn[stk[hd]]>dfn[lca]){
     79             if(lst) connect(lst,stk[hd]);
     80             lst=stk[hd--];
     81         }if(stk[hd]!=lca) stk[++hd]=lca,id[++pct]=lca;
     82         if(lst) connect(lst,stk[hd]);
     83         if(h[i]!=1) stk[++hd]=h[i];
     84     }
     85     while(hd>1) connect(stk[hd],stk[hd-1]),hd--;
     86 }
     87 pa up[maxn],dw[maxn];
     88 inline void dfs2(int x){
     89     if(rea[x]) dw[x]=mp(0,x);
     90     else dw[x]=mp(inf,0);
     91     for(int i=xsh[x];i;i=xbr[i]){
     92         dfs2(i);
     93         dw[x]=min(dw[x],mp(dw[i].first+len[i],dw[i].second));
     94     }
     95 }
     96 inline void dfs3(int x){
     97     if(rea[x]) up[x]=mp(0,x);
     98     else if(x==1) up[x]=mp(inf,0);
     99     pa m=mp(inf,0),s=mp(inf,0);
    100     for(int i=xsh[x];i;i=xbr[i]){
    101         s=min(s,mp(dw[i].first+len[i],dw[i].second));
    102         if(s<m) swap(s,m);
    103     }
    104     for(int i=xsh[x];i;i=xbr[i]){
    105         up[i]=mp(up[x].first+len[i],up[x].second);
    106         if(dw[i].first+len[i]==m.first&&dw[i].second==m.second){
    107             up[i]=min(up[i],mp(s.first+len[i],s.second));
    108         }else up[i]=min(up[i],mp(m.first+len[i],m.second));
    109         dfs3(i);
    110     }
    111     if(x!=1){
    112         int n=min(dw[x],up[x]).first+len[x]+min(dw[xfa[x]],up[xfa[x]]).first,mi=min(dw[xfa[x]],up[xfa[x]]).second;
    113         if(!(n&1)&&mi<min(dw[x],up[x]).second) n--;
    114         n>>=1,n-=min(dw[x],up[x]).first;
    115         if(n>len[x]) n--;
    116         if(n>=0){
    117             int y=jump(x,n),z=jump(x,len[x]-1);
    118             ans[min(dw[x],up[x]).second]+=siz[y]-siz[x],ans[mi]+=siz[z]-siz[y];
    119         }
    120         
    121     }
    122     int ss=siz[x];
    123     for(int i=xsh[x];i;i=xbr[i]) ss-=siz[jump(i,len[i]-1)];
    124     ans[min(dw[x],up[x]).second]+=ss;
    125 }
    126 
    127 
    128 int hh[maxn];
    129 int main(){
    130     //freopen("","r",stdin);
    131     int i,j,k;
    132     N=rd();
    133     for(i=1;i<N;i++){
    134         int a=rd(),b=rd();
    135         adeg(a,b);adeg(b,a);
    136     }dep[1]=1;dfs1(1);
    137     // for(i=1;i<=N;i++) printf("~%d %d
    ",i,siz[i]);
    138     Q=rd();
    139     for(i=1;i<=Q;i++){
    140         int m=rd();
    141         for(j=1;j<=m;j++) hh[j]=h[j]=rd();
    142         build(m);
    143         dfs2(1),dfs3(1);
    144         for(j=1;j<=m;j++) printf("%d ",ans[hh[j]]);
    145         printf("
    ");
    146         for(;pct;pct--) xfa[id[pct]]=xbr[id[pct]]=xsh[id[pct]]=rea[id[pct]]=ans[id[pct]]=0;
    147     }
    148     return 0;
    149 }
    150 /*
    151 21
    152 1 2
    153 2 3
    154 2 4
    155 3 9
    156 4 5
    157 5 6
    158 6 7
    159 6 8
    160 2 18 2 19 2 20 2 21
    161 9 13 9 14
    162 5 17
    163 4 15 4 16
    164 6 10 10 11 10 12
    165 1
    166 3
    167 9 7 8
    168 */
  • 相关阅读:
    assert用法,原理,改编(C++)
    使用临界段实现优化的进程间同步对象原理和实现 (转)
    去除表达式里面多余的()
    为什么C++编译器不能支持对模板的分离式编译
    python试题[转]
    从CSDN的趣味题学Python
    即时战略游戏中如何协调对象移动
    贪心算法精讲
    游戏引擎大全
    I/O 完成端口( Windows核心编程 )
  • 原文地址:https://www.cnblogs.com/Ressed/p/9997771.html
Copyright © 2020-2023  润新知