CF 1172E Nauuo and ODT ——LCT

题目:http://codeforces.com/contest/1172/problem/E

LCT好题。

考虑对每个颜色求出 “不是该颜色的点组成的连通块的 siz2 之和” 。每个颜色用 LCT 维护不是该颜色的点。

LCT 维护的一个连通块,其最顶端的点是该颜色,其他部分满足 “不是该颜色” ;再维护子树的 siz2 ,就能做了。

注意代码里的 p[ ] 要开 2*n 那么大!!!

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
ll Sqr(int x){return (ll)x*x;}
const int N=4e5+5,M=N<<1;
int n,m,col[N],hd[N],xnt,to[M],nxt[M];
int f[N],fa[N],c[N][2],siz[N],sizi[N];
int p[M],tot; bool vis[N];ll siz2i[N],tmp,dlt[N];//p[M]!!
bool isrt(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
void pshp(int x){siz[x]=siz[c[x][0]]+siz[c[x][1]]+sizi[x]+1;}
void rotate(int x)
{
  int y=fa[x],z=fa[y]; bool d=(x==c[y][1]);
  if(!isrt(y))c[z][y==c[z][1]]=x;
  fa[x]=z; fa[y]=x; fa[c[x][!d]]=y;
  c[y][d]=c[x][!d]; c[x][!d]=y;
  pshp(y); pshp(x);
}
void splay(int x)
{
  for(int y,z;!isrt(x);rotate(x))
    {
      y=fa[x]; z=fa[y];
      if(!isrt(y))
    ((y==c[z][0])^(x==c[y][0]))?rotate(x):rotate(y);
    }
}
void access(int x)
{
  for(int t=0;x;t=x,x=fa[x])
    {
      splay(x); int y=c[x][1];
      sizi[x]+=siz[y]; siz2i[x]+=Sqr(siz[y]);
      sizi[x]-=siz[t]; siz2i[x]-=Sqr(siz[t]);
      c[x][1]=t; pshp(x);
    }
}
int fnd_rt(int x)
{
  access(x); splay(x);
  while(c[x][0])x=c[x][0];
  splay(x); return x;
}
void link(int x)
{
  splay(x);//x is top so always accessed
  tmp-=Sqr(siz[c[x][1]])+siz2i[x];
  int y=f[x],rt=fnd_rt(y);//rt splayed
  splay(rt);///y accessed
  tmp-=Sqr(siz[c[rt][1]]);////+siz2i[rt];
  splay(y); fa[x]=y;
  sizi[y]+=siz[x]; siz2i[y]+=Sqr(siz[x]); pshp(y);
  access(x); splay(rt);//access(x)!!!
  tmp+=Sqr(siz[c[rt][1]]);
}
void cut(int x)
{
  int rt=fnd_rt(x);//x accessed//rt splayed
  tmp+=siz2i[x];//!!!
  tmp-=Sqr(siz[c[rt][1]]);
  int y=f[x]; splay(y); c[y][1]=0; fa[x]=0; pshp(y);
  //x accessed and is bottom so is c[y][1]
  splay(rt);
  tmp+=Sqr(siz[c[rt][1]]);
}
namespace Q{
  int hd[N],xnt,to[M],id[M],nxt[M];
  void add(int x,int y,int i)
  {
    to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;id[xnt]=i;
  }
  void solve(int cr)
  {
    tot=0;
    for(int i=hd[cr];i;i=nxt[i])
      p[++tot]=i;
    for(int i=tot,d;i;i--)
      {
    tmp=0; d=p[i];
    if(vis[to[d]]) link(to[d]);
    else cut(to[d]);
    dlt[id[d]]+=tmp;
    vis[to[d]]^=1;
      }
  }
  void solve2(int cr)
  {
    for(int i=hd[cr];i;i=nxt[i])
      {
    tmp=0;
    if(vis[to[i]]) link(to[i]);
    else cut(to[i]);
    vis[to[i]]^=1;
      }
  }
}
namespace I{
  int hd[N],xnt,to[N],nxt[N];
  void add(int x,int y)
  {to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
  void solve(int cr)
  {
    tot=0;
    for(int i=hd[cr];i;i=nxt[i])
      p[++tot]=to[i];
    tmp=0;
    for(int i=tot;i;i--)
      {
    if(vis[p[i]]) link(p[i]);
    else cut(p[i]);
    vis[p[i]]^=1;
      }
    dlt[0]+=tmp;
  }
  void solve2(int cr)
  {
    for(int i=hd[cr];i;i=nxt[i])
      {
    tmp=0;
    if(vis[to[i]]) link(to[i]);
    else cut(to[i]);
    vis[to[i]]^=1;///
      }
  }
}
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void ini_dfs(int cr,int fa)
{
  f[cr]=fa;
  for(int i=hd[cr],v;i;i=nxt[i])
    if((v=to[i])!=fa) ini_dfs(v,cr);
}
int main()
{
  n=rdn();m=rdn();
  for(int i=2;i<=n+1;i++)
    { col[i]=rdn(); I::add(col[i],i);}
  for(int i=1,u,v;i<n;i++)
    u=rdn()+1,v=rdn()+1,add(u,v),add(v,u);
  add(1,2); add(2,1); ini_dfs(1,0);
  for(int i=1,u,d;i<=m;i++)
    {
      u=rdn()+1; d=rdn(); Q::add(col[u],u,i);
      col[u]=d; Q::add(d,u,i);
    }
  for(int i=2;i<=n+1;i++)siz[i]=1;//
  for(int i=2;i<=n+1;i++) link(i);
  dlt[0]=(ll)n*n*n;
  for(int i=1;i<=n;i++)
    {
      I::solve(i); Q::solve(i);
      Q::solve2(i); I::solve2(i);
    }
  ll ans=(ll)n*n*n;
  for(int i=0;i<=m;i++)
    {
      ans-=dlt[i]; printf("%lld\n",ans);
    }
  return 0;
}
View Code

 

posted on 2019-06-10 20:44  Narh  阅读(220)  评论(0编辑  收藏  举报

导航