zoukankan      html  css  js  c++  java
  • [点分治] Luogu P2664 树上游戏

    题解

    • 对于树中的一点i,如果该点的颜色在该点到根这条链上是第一次出现,那么对于这棵树的其他点j(以i和j的lca为根),均能与i的子树(包括i)组成点对,i的颜色会对j的答案贡献size[i]
    • 然后点分治就可以解决了

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #define ll long long
     4 using namespace std;
     5 const int N=2e5+10,inf=1e8;
     6 int n,cnt=1,root,head[N],v[N],vis[N*2];
     7 ll q,sum,num,tot,Mx=inf,size[N],col[N],ans[N],p[N];
     8 struct edge { int to,from; }e[N*2];
     9 void clear(int x,int fa) { p[v[x]]=col[v[x]]=0; for (int i=head[x];i;i=e[i].from) if (!vis[i]&&e[i].to!=fa) clear(e[i].to,x); }
    10 void insert(int x,int y)
    11 {
    12     e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt;
    13     e[++cnt].to=x,e[cnt].from=head[y],head[y]=cnt;
    14 }
    15 void dfs1(int x,int fa)
    16 {
    17     size[x]=1,p[v[x]]++;
    18     for (int i=head[x];i;i=e[i].from) if (e[i].to!=fa&&!vis[i]) dfs1(e[i].to,x),size[x]+=size[e[i].to];
    19     if (p[v[x]]==1) sum+=size[x],col[v[x]]+=size[x];
    20     p[x[v]]--;
    21 }
    22 void dfs2(int x,int fa)
    23 {
    24     p[v[x]]++;
    25     if (p[v[x]]==1) sum-=col[v[x]],num++;
    26     ans[x]+=sum+num*q;
    27     for (int i=head[x];i;i=e[i].from) if (!vis[i]&&e[i].to!=fa) dfs2(e[i].to,x);
    28     if (p[v[x]]==1) sum+=col[v[x]],num--;
    29     p[v[x]]--;
    30 }
    31 void findroot(int x,int fa)
    32 {
    33     size[x]=1; ll mx=0;
    34     for (int i=head[x];i;i=e[i].from) if (e[i].to!=fa&&!vis[i]) findroot(e[i].to,x),size[x]+=size[e[i].to],mx=max(mx,size[e[i].to]);
    35     mx=max(mx,tot-size[x]);
    36     if (mx<Mx) Mx=mx,root=x;
    37 }
    38 void change(int x,int fa,int k)
    39 {
    40     p[v[x]]++;
    41     for (int i=head[x];i;i=e[i].from) if (e[i].to!=fa&&!vis[i]) change(e[i].to,x,k);
    42     if (p[v[x]]==1) sum+=(ll)size[x]*k,col[v[x]]+=(ll)size[x]*k;
    43     p[v[x]]--;
    44 }
    45 void solve(int x,int fa)
    46 {
    47     dfs1(x,fa),ans[x]+=sum-col[v[x]]+size[x];
    48     for (int i=head[x];i;i=e[i].from) if (!vis[i]&&e[i].to!=fa)
    49         p[v[x]]++,sum-=size[e[i].to],col[v[x]]-=size[e[i].to],change(e[i].to,x,-1),p[v[x]]--,q=size[x]-size[e[i].to],dfs2(e[i].to,x),p[v[x]]++,sum+=size[e[i].to],col[v[x]]+=size[e[i].to],change(e[i].to,x,1),p[v[x]]--;
    50     sum=0,num=0,clear(x,fa);
    51     for (int i=head[x];i;i=e[i].from) if (!vis[i]&&e[i].to!=fa) vis[i]=1,vis[i^1]=1,tot=size[e[i].to],Mx=inf,findroot(e[i].to,x),solve(root,0);
    52 }
    53 int main()
    54 {
    55     scanf("%d",&n);
    56     for (int i=1;i<=n;i++) scanf("%d",&v[i]);
    57     for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),insert(x,y);
    58     tot=n,findroot(1,0),solve(root,0);
    59     for (int i=1;i<=n;i++) printf("%lld
    ",ans[i]);
    60 }
  • 相关阅读:
    SAP BW维护项目中的常见问题 沧海
    从印度英语想到creole 沧海
    侃State模式
    住在“天堂”的代价一个工薪阶层买房的感受
    家庭财务总管软件设计
    侃观察者模式(Observer)
    软件设计起步:画UML类图
    一个提醒软件---好朋友
    学习设计模式的一些心得
    一次偶然结对编程的感受
  • 原文地址:https://www.cnblogs.com/Comfortable/p/11329694.html
Copyright © 2011-2022 走看看