Blue and Red Tree题解

Blue and Red Tree题解

首先,我们很容易发现在两棵树上连接相同的点的边无需删去。
接着,首先删那条边?
我们把红树上不与蓝树重合的边看作覆盖蓝树边的路径,
那么,我们首先删除被红树边覆盖多次的边么?
肯定不行,删除这条边后,就不存在构成其他覆盖这条蓝边的红边所需的蓝边链了。
所以,我们每次找出只被覆盖一次的蓝边,删去覆盖它的红遍,并去除红边影响,如果做到最后,自然可以。

代码:

#include<bits/stdc++.h>
#define lc (x<<1)
#define rc (x<<1|1) 
using namespace std;
const int N=60006,inf=1e9,mod=201314;
int n,m,t1,t2,t3,cnt=0,dfn=0,tot=0,f[N],a[N],d[N],son[N],siz[N],num[N],top[N],lazy[N<<2],w[N<<2],head[N],ans[N];
struct xd{int i,flag,x,y;}q[N<<1];
struct edge{int nxt,to;}e[N<<1];
inline void add(int u,int v){e[++cnt].nxt=head[u],e[cnt].to=v,head[u]=cnt;}
inline int read(){
   int T=0,F=1; char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();}
   while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar();
   return F*T;
}
void dfs(int x){
     d[x]=d[f[x]]+1,siz[x]=1; int maxt=0,maxa=-1;
     for(int i=head[x];i;i=e[i].nxt){
            dfs(e[i].to),siz[x]+=siz[e[i].to];
            if(maxa<siz[e[i].to]) maxt=e[i].to,maxa=siz[maxt];
         } 
     son[x]=maxt;
}
void dfs2(int x,int topx){
     num[x]=++dfn,top[x]=topx; 
     if(son[x]) dfs2(son[x],topx);
     for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=f[x]&&e[i].to!=son[x]) dfs2(e[i].to,e[i].to); 
}
void pushdown(int x,int len){if(lazy[x]) lazy[lc]=(lazy[lc]+lazy[x])%mod,lazy[rc]=(lazy[rc]+lazy[x])%mod,w[lc]=(w[lc]+lazy[x]*(len-(len>>1))%mod)%mod,w[rc]=(w[rc]+lazy[x]*(len>>1)%mod)%mod,lazy[x]=0;}
void update(int l,int r,int p,int q,int x,int y){
     if(p<=l&&r<=q){w[x]=(w[x]+(r-l+1)*y%mod)%mod,lazy[x]=(lazy[x]+y)%mod; return;}
     pushdown(x,r-l+1);
     int mid=l+r>>1;
     if(p<=mid) update(l,mid,p,q,lc,y);
     if(q>mid) update(mid+1,r,p,q,rc,y);
     w[x]=(w[lc]+w[rc])%mod;
}
int query(int l,int r,int p,int q,int x){
     if(p<=l&&r<=q) return w[x];
     pushdown(x,r-l+1);
     int mid=l+r>>1,ans=0;
     if(p<=mid) ans=query(l,mid,p,q,lc);
     if(q>mid) ans=(ans+query(mid+1,r,p,q,rc))%mod;
     return ans;
}
void lj_update(int x,int y){
    while(top[x]!=top[y]){
         if(d[top[x]]<d[top[y]]) swap(x,y);
         update(1,n,num[top[x]],num[x],1,1);
         x=f[top[x]];
    }
    if(d[x]>d[y]) swap(x,y);
    update(1,n,num[x],num[y],1,1); 
}
int lj_query(int x,int y){
    int ans=0;
    while(top[x]!=top[y]){
         if(d[top[x]]<d[top[y]]) swap(x,y);
         ans=(ans+query(1,n,num[top[x]],num[x],1))%mod;
         x=f[top[x]];
    }
    if(d[x]>d[y]) swap(x,y);
    ans=(ans+query(1,n,num[x],num[y],1))%mod; 
    return ans;
}
bool cmp(xd u,xd v){return u.x<v.x;}
int main(){
    n=read(),m=read();
    for(int i=2;i<=n;++i) f[i]=read()+1,add(f[i],i);
    dfs(1),dfs2(1,1);
    for(int i=1;i<=m;++i){
        t1=read(),t2=read()+1,t3=read()+1;
        q[++tot].flag=0,q[tot].i=i,q[tot].x=t1,q[tot].y=t3;
        q[++tot].flag=1,q[tot].i=i,q[tot].x=t2,q[tot].y=t3; 
    }
    sort(q+1,q+tot+1,cmp),q[0].x=0;
    for(int i=1;i<=tot;++i){
        for(int j=q[i-1].x+1;j<=q[i].x;++j)
            lj_update(1,j);
        if(!q[i].flag) ans[q[i].i]=-lj_query(1,q[i].y);
        else ans[q[i].i]=(ans[q[i].i]+lj_query(1,q[i].y)+mod)%mod;
    }
    for(int i=1;i<=m;++i) printf("%d\n",ans[i]);
    return 0;
}  

转载于:https://www.cnblogs.com/ljk123-de-bo-ke/p/11396424.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值