zoukankan      html  css  js  c++  java
  • [HNOI2014][bzoj3572] 世界树 [虚树+dp]

    题面:

    传送门

    思路:

    一道虚树的好题,是很多虚树博客的入门题目

    但是我认为这道题目出的难点和亮点不在于虚树,而在于建出虚树以后dp的思路与实现

    下文中为方便描述,用势力范围来表示一个“议事处”管辖的节点集合

    首先,看完题目以后一个直观的感受,就是我去考虑两个询问点之间,哪些点属于谁的势力范围,然后这样

    这是个类似暴力的东西

    那树上路径的中点怎么求?可以lca求出距离以后倍增

    但是现在问题来了,虚树上的节点有的是询问点,有的只是询问点的lca,并不参与询问,怎么解决这个问题呢?

    而且在那个初始想法中,有一些路径是势必会重复的,又怎么解决?

    一个直观的想法就是把一堆路径询问简化掉

    我们发现一个点终究只能属于一个询问点的势力范围,那么一条边上的节点同理

    所以我们可以把重复经过同一条边的询问拆到每条虚树边上,然后对于每条虚树边来考虑解题

    显然,虚树边分为两种:两边的虚树点被同一个节点控制的,或者两端被不同节点控制的

    对于两端被同一个询问点控制的边,显然这条虚树边上的所有的点的所有子树都被这个点控制

    另一种情况则是在中间有一个分界线,界线一边的点与它们的子树被那一边的端点的“主人”控制

    那么也就是说,我们只需要处理出虚树上的每一个节点被哪个询问点控制,然后对于上面的两种情况分别考虑、统计答案就行了

    那么怎么处理这个控制关系呢?

    我们做两次dfs

    第一次,我们求出某个虚树节点的所有儿子中离它最近的控制点

    第二次,则用父亲的控制点(和儿子不在同一个子树中)来更新儿子的控制点

    dp的时候则是依然用倍增来实现跳到分界点上

    两个点之间的距离则可以用lca实现

    大概就是这样了,更具体的内容可以参考代码

    Code:

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<algorithm>
      5 #define ll long long
      6 #define inf 1e9
      7 using namespace std;
      8 inline int read(){
      9     int re=0,flag=1;char ch=getchar();
     10     while(ch>'9'||ch<'0'){
     11         if(ch=='-') flag=-1;
     12         ch=getchar();
     13     }
     14     while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
     15     return re*flag;
     16 }
     17 int n,dep[300010],siz[300010],st[300010][20],dfn[300010],clk;
     18 struct graph{
     19     int first[300010],cnt;
     20     struct edge{
     21         int to,next;
     22     }a[600010];
     23     inline void add(int u,int v){
     24         if(u==v) return;
     25         a[++cnt]=(edge){v,first[u]};first[u]=cnt;
     26     }
     27     graph(){
     28         memset(first,-1,sizeof(first));cnt=0;
     29     }
     30     void init(){cnt=0;}
     31 }G,g;
     32 void dfs(int u,int f){
     33 //  cout<<"begin dfs "<<u<<endl;
     34     int i,v;
     35     dep[u]=dep[f]+1;st[u][0]=f;dfn[u]=++clk;siz[u]=1;
     36     for(i=G.first[u];~i;i=G.a[i].next){
     37         v=G.a[i].to;
     38         if(v==f) continue;
     39         dfs(v,u);siz[u]+=siz[v];
     40     }
     41 //  cout<<"end of dfs "<<u<<ends<<dep[u]<<ends<<siz[u]<<endl;
     42     return;
     43 }
     44 void ST(){
     45     int i,j;
     46     for(j=1;j<=19;j++) for(i=1;i<=n;i++) st[i][j]=st[st[i][j-1]][j-1];
     47 }
     48 int lca(int l,int r){
     49     if(dep[l]>dep[r]) swap(l,r);
     50     int i;
     51     for(i=19;i>=0;i--) if(dep[st[r][i]]>=dep[l]) r=st[r][i];
     52     if(l==r) return l;
     53     for(i=19;i>=0;i--)
     54         if(st[r][i]!=st[l][i]){
     55             r=st[r][i];
     56             l=st[l][i];
     57         }
     58     return st[l][0];
     59 }
     60 int q[300010],ans[300010],num[300010],s[300010],top;
     61 bool vis[300010];
     62 bool cmp1(int l,int r){
     63     return dfn[l]<dfn[r];
     64 }
     65 bool cmp2(int l,int r){
     66     return num[l]<num[r];
     67 }
     68 int minn[300010],belong[300010],sur[300010];
     69 int dis(int l,int r){return dep[l]+dep[r]-2*dep[lca(l,r)];}
     70 void dfs1(int u){
     71     int i,v,d1,d2;belong[u]=(vis[u]?u:0);sur[u]=siz[u];
     72     for(i=g.first[u];~i;i=g.a[i].next){
     73         v=g.a[i].to;dfs1(v);
     74         d1=dep[belong[v]]-dep[u];d2=(belong[u]?dep[belong[u]]-dep[u]:inf);
     75         if(d1<d2||(d1==d2&&belong[v]<belong[u])) belong[u]=belong[v];
     76     }
     77 }
     78 void dfs2(int u){
     79     int i,v,d1,d2;
     80     for(i=g.first[u];~i;i=g.a[i].next){
     81         v=g.a[i].to;d1=dis(belong[u],v);d2=dis(belong[v],v);
     82         if(d1<d2||(d1==d2&&belong[u]<belong[v])) belong[v]=belong[u];
     83         dfs2(v);
     84     }
     85 }
     86 void dp(int u){
     87 //  cout<<"enter dp "<<u<<ends<<belong[u]<<endl;
     88     int i,v,d1,d2,mid,tv,j,tmp;
     89     for(i=g.first[u];~i;i=g.a[i].next){
     90         v=g.a[i].to;g.first[u]=g.a[i].next;mid=tv=v;
     91 //      cout<<"going to "<<v<<endl;
     92         dp(v);
     93         for(j=19;j>=0;j--) if(dep[st[tv][j]]>dep[u]) tv=st[tv][j];
     94         sur[u]-=siz[tv];
     95 //      cout<<"edge up to "<<tv<<endl;
     96         if(belong[u]==belong[v]){
     97             ans[belong[u]]+=siz[tv]-siz[v];continue;
     98         }
     99         for(j=19;j>=0;j--){
    100             tmp=st[mid][j];if(dep[tmp]<=dep[u]) continue;
    101             d1=dis(tmp,belong[v]);d2=dis(tmp,belong[u]);
    102             if(d1<d2||(d1==d2&&belong[v]<belong[u])) mid=tmp;
    103         }
    104 //      cout<<"********diff edge "<<mid<<endl;
    105         ans[belong[u]]+=siz[tv]-siz[mid];
    106         ans[belong[v]]+=siz[mid]-siz[v];
    107     }
    108 //  cout<<"end of dp "<<u<<ends<<sur[u]<<endl;
    109     ans[belong[u]]+=sur[u];
    110 }
    111 void solve(){
    112 //  cout<<"*************************enter solve
    ";
    113     int m=read(),i,grand;
    114     for(i=1;i<=m;i++) q[i]=read(),num[q[i]]=i,vis[q[i]]=1;;
    115     sort(q+1,q+m+1,cmp1);top=0;g.init();s[++top]=1;
    116     for(i=1;i<=m;i++){
    117 //      if(!top){s[++top]=q[i];continue;}
    118         grand=lca(s[top],q[i]);
    119         while(1){
    120             if(dep[s[top-1]]<=dep[grand]){
    121                 g.add(grand,s[top--]);
    122                 if(s[top]!=grand) s[++top]=grand;
    123                 break;
    124             }
    125             g.add(s[top-1],s[top]);top--;
    126         }
    127         if(s[top]!=q[i]) s[++top]=q[i];
    128     }
    129     while(--top>=1) g.add(s[top],s[top+1]); 
    130     dfs1(s[1]);dfs2(s[1]);dp(s[1]);
    131     sort(q+1,q+m+1,cmp2);
    132 //  for(i=1;i<=m;i++) cout<<q[i]<<ends;cout<<endl;
    133     for(i=1;i<=m;i++) vis[q[i]]=0,num[q[i]]=inf,printf("%d ",ans[q[i]]),ans[q[i]]=0;
    134     puts("");
    135 }
    136 int main(){
    137 //  cout<<"begin
    ";
    138     int i,t1,t2;
    139     n=read();memset(num,0x3f,sizeof(num));
    140 //  cout<<"input n "<<n<<endl;
    141     for(i=1;i<n;i++){
    142         t1=read();t2=read();
    143         G.add(t1,t2);G.add(t2,t1);
    144     }
    145 //  cout<<"input of tree end
    ";
    146     dfs(1,0);ST();
    147     int Q=read();
    148     for(i=1;i<=Q;i++) solve();
    149 }
  • 相关阅读:
    正则表达式
    DNS协议相关命令 dig
    Linux下 redsocks + iptables + socks5 实现全局代理
    Kotlin native 初心
    Kotlin 初心
    XMLHttpRequest2 实现AJAX跨域请求
    CSS、JavaScript 初心
    jQuery 初心
    java.lang.ClassNotFoundException 解决方案
    CPU 负荷过重时邮件报警
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/8570174.html
Copyright © 2011-2022 走看看