enos - 动态dp

题目大意:给一棵树,每个点有三种颜色,初始全为0,。若干次操作每次操作形如将x到y路径上的点颜色全部改为c,或者询问某个点所在的同色连通块大小。 n , q ≤ 1 0 5 n,q\le10^5 n,q105
题解:显然可以动态dp……

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
namespace INPUT_SPACE{
    const int BS=(1<<24)+5;char Buffer[BS],*HD,*TL;inline int gc() { if(HD==TL) TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);return (HD==TL)?EOF:*HD++; }
    inline int inn() { int x,ch;while((ch=gc())<'0'||ch>'9');x=ch^'0';while((ch=gc())>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return x; }
}using INPUT_SPACE::inn;
const int N=100002;struct edges{ int to,pre; }e[N];
int h[N],etop,d[N],fa[N],sz[N],son[N],top[N],in[N],bot[N],tms[N],dfc,lst[N];
inline int add_edge(int u,int v) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop; }
struct msg{
    int sz[3],col,lc,ans;msg() { sz[0]=sz[1]=sz[2]=0,lc=col=-1,ans=0; }
    inline int operator=(int c) { return ans=sz[c],lc=col=c; }
    inline msg operator+(const msg &v)const
    {
        msg res;rep(i,0,2) res.sz[i]=sz[i]+v.sz[i];
        if(col^v.col) res.col=-1;else res.col=col;res.lc=lc;
        res.ans=ans;if(col>=0&&col==v.lc) res.ans+=v.ans;return res;
    }
    inline msg& operator+=(const msg &v) { return (*this)=(*this)+v,*this; }
};
struct segment{ int l,r,t;msg v;segment *ch[2]; }*rt[N];
inline int push_up(segment* &rt) { return rt->v=rt->ch[0]->v+rt->ch[1]->v,0; }
inline int build(segment* &rt,int l,int r)
{
    rt=new segment,rt->l=l,rt->r=r,rt->t=-1;int mid=(l+r)>>1,x;
    if(l==r) return x=tms[l],rt->v.ans=rt->v.sz[0]=sz[x]-sz[son[x]],rt->v.sz[1]=rt->v.sz[2]=1,rt->v.col=rt->v.lc=0;
    return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r),push_up(rt);
}
inline int push_down(segment* &rt) { return rt->ch[0]->v=rt->ch[1]->v=rt->ch[0]->t=rt->ch[1]->t=rt->t,rt->t=-1; }
inline int update(segment* &rt,int p,int c,int v)
{
    int l=rt->l,r=rt->r,mid=(l+r)>>1;if(l==r) return rt->v.sz[c]+=v,rt->v.ans=rt->v.sz[rt->v.col];
    if(rt->t>=0) push_down(rt);return update(rt->ch[p>mid],p,c,v),push_up(rt);
}
inline int cover(segment* &rt,int s,int t,int c)
{
    int l=rt->l,r=rt->r,mid=(l+r)>>1;if(s<=l&&r<=t) return rt->v=rt->t=c;if(rt->t>=0) push_down(rt);
    if(s<=mid) cover(rt->ch[0],s,t,c);if(mid<t) cover(rt->ch[1],s,t,c);return push_up(rt);
}
inline msg query(segment* &rt,int s,int t)
{
    int l=rt->l,r=rt->r,mid=(l+r)>>1;if(s<=l&&r<=t) return rt->v;if(rt->t>=0) push_down(rt);
    if(t<=mid) return query(rt->ch[0],s,t);if(mid<s) return query(rt->ch[1],s,t);return query(rt->ch[0],s,t)+query(rt->ch[1],s,t);
}
inline int col(int x) { return query(rt[top[x]],in[x],in[x]).col; }
int fir_dfs(int x,int f=0)
{
    d[x]=d[fa[x]=f]+1;
    for(int i=h[x],y;i;i=e[i].pre) sz[x]+=fir_dfs(y=e[i].to,x),(sz[y]>sz[son[x]]?son[x]=y:0);
    return ++sz[x];
}
int sec_dfs(int x)
{
    tms[in[x]=++dfc]=x;
    if(son[x]) son[x][top]=top[x],sec_dfs(son[x]),bot[x]=bot[son[x]];
    else bot[x]=x;
    for(int i=h[x],y;i;i=e[i].pre) if((y=e[i].to)^son[x]) top[y]=y,sec_dfs(y);
    if(x==top[x]) build(rt[x],in[x],in[bot[x]]);return 0;
}
inline int getLCA(int x,int y) { for(;top[x]^top[y];x=top[x][fa]) if(d[top[x]]<d[top[y]]) swap(x,y);return d[x]<d[y]?x:y; }
inline int update(int x,int c,int v)
{
    int cnt=0;for(int y=top[x],z=fa[y];z;z=fa[y=top[z]]) lst[++cnt]=y;
    for(int i=cnt,y,z;i;i--) y=lst[i],z=fa[y],update(rt[top[z]],in[z],col(y),-rt[y]->v.ans);
    for(int y=x,z=top[x];d[y]>=d[c];z=top[y=fa[z]]) cover(rt[z],max(in[z],in[c]),in[y],v);
    for(int i=1,y,z;i<=cnt;i++) y=lst[i],z=fa[y],update(rt[top[z]],in[z],col(y),rt[y]->v.ans);
    return 0;
}
inline int update(int x,int y,int c,int v) { if(x==c) return update(y,c,v);if(y==c) return update(x,c,v);return update(x,c,v),update(y,c,v); }
inline int query(int x)
{
    int c=col(x);
    for(int y=top[x],z=fa[y];z;z=fa[y=top[z]]) if(query(rt[y],in[y],in[x]).col==c&&col(z)==c) x=z;else break;
    int y=top[x],L=in[y],R=in[x];
    while(L<=R) { int mid=(L+R)>>1;if(query(rt[y],mid,in[x]).col==c) R=mid-1;else L=mid+1; }
    return x=tms[L],query(rt[y],in[x],in[bot[x]]).ans;
}
int main()
{
    int n=inn(),m=inn(),x,y;rep(i,2,n) add_edge(inn(),i);fir_dfs(1),top[1]=1,sec_dfs(1);
    while(m--) if(inn()==1) x=inn(),y=inn(),update(x,y,getLCA(x,y),inn());else printf("%d\n",query(inn()));
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值