[bzoj4154][Ipsc2015]Generating Synergy

4154: [Ipsc2015]Generating Synergy

Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 306 Solved: 122
[Submit][Status][Discuss]
Description

给定一棵以1为根的有根树,初始所有节点颜色为1,每次将距离节点a不超过l的a的子节点染成c,或询问点a的颜色
Input

第一行一个数T,表示数据组数
接下来每组数据的第一行三个数n,c,q表示结点个数,颜色数和操作数
接下来一行n-1个数描述2..n的父节点
接下来q行每行三个数a,l,c
若c为0,表示询问a的颜色
否则将距离a不超过l的a的子节点染成c
Output

设当前是第i个操作, yi 为本次询问的答案(若本次操作是一个修改则 yi 0 ),令zi=iyi,请输出 z1+z2+...+zq 109+7
Sample Input

1

4 3 7

1 2 2

3 0 0

2 1 3

3 0 0

1 0 2

2 0 0

4 1 1

4 0 0

Sample Output

32  

HINT

1,3,5,7 的询问的答案分别为 1,3,3,1 ,所以答案为 11+20+33+40+53+60+71=32.

数据范围:

对于100%的数据T<=6,n,m,c<=10^5,

1<=a<=n,0<=l<=n,0<=c<=c

因为只有子节点,所以把树上的每个点都对应到二维平面中取。
pos[x] 表示 x dfs序, deep[x] 表示 x 的深度,每个点的坐标就是:(pos[x],deep[x])
染色就是给区间 (L[a],R[a],deep[a],deep[a]+l) 赋值。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
#define Mod 1000000007
const int N=100010;
struct E{int st,en;}aa[N<<1];
int T,n,m,tot,point[N],next[N<<1],pos[N],dfsn,deep[N],root,D,L[N],R[N];
struct S{
    int c,de,d[2],mi[2],ma[2],l,r;
    int &operator [] (int x){
        return d[x];
    }
    bool operator == (const S &x)const{
        return d[0]==x.d[0]&&d[1]==x.d[1];
    }
    bool operator < (const S &x)const{
        return d[D]==x.d[D]?d[D^1]<x.d[D^1]:d[D]<x.d[D];
    }
}tr[N],p[N],now;
inline int in(){
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}
inline void add(int x,int y){
    next[++tot]=point[x];point[x]=tot;
    aa[tot].st=x;aa[tot].en=y;
    next[++tot]=point[y];point[y]=tot;
    aa[tot].st=y;aa[tot].en=x;
}
inline void dfs(int x,int last){
    int i;
    L[x]=R[x]=pos[x]=++dfsn;
    for(i=point[x];i;i=next[i])
      if(aa[i].en!=last){
        deep[aa[i].en]=deep[x]+1;
        dfs(aa[i].en,x);
        R[x]=max(R[x],R[aa[i].en]);
      }
}
inline void update(int k){
    int l=tr[k].l,r=tr[k].r,i;
    for(i=0;i<=1;++i){
        tr[k].mi[i]=tr[k].ma[i]=tr[k][i];
        if(l){
            tr[k].mi[i]=min(tr[k].mi[i],tr[l].mi[i]);
            tr[k].ma[i]=max(tr[k].ma[i],tr[l].ma[i]);
        }
        if(r){
            tr[k].mi[i]=min(tr[k].mi[i],tr[r].mi[i]);
            tr[k].ma[i]=max(tr[k].ma[i],tr[r].ma[i]);
        }
    }
}
#define mid (l+r)/2
inline int build(int l,int r,int flag){
    if(l>r) return 0;
    D=flag;nth_element(p+l,p+mid,p+r+1);
    tr[mid]=p[mid];
    tr[mid].l=build(l,mid-1,flag^1);
    tr[mid].r=build(mid+1,r,flag^1);
    update(mid);
    return mid;
}
inline bool in(int k,int x1,int y1,int x2,int y2){
    return tr[k].mi[0]>=x1&&tr[k].ma[0]<=y1&&tr[k].mi[1]>=x2&&tr[k].ma[1]<=y2;
}
inline bool out(int k,int x1,int y1,int x2,int y2){
    return tr[k].mi[0]>y1||tr[k].ma[0]<x1||tr[k].mi[1]>y2||tr[k].ma[1]<x2;
}
inline bool in1(int k,int x1,int y1,int x2,int y2){
    return tr[k][0]>=x1&&tr[k][0]<=y1&&tr[k][1]>=x2&&tr[k][1]<=y2;
}
inline void pushdown(int k){
    int l=tr[k].l,r=tr[k].r,c=tr[k].de;
    if(l) tr[l].de=tr[l].c=c;
    if(r) tr[r].de=tr[r].c=c;
    tr[k].de=0;
}
inline void insert(int k,int x1,int y1,int x2,int y2,int c){
    if(x1>y1||x2>y2||!k) return ;
    if(in(k,x1,y1,x2,y2)){
        tr[k].de=tr[k].c=c;
        return ;
    }
    if(out(k,x1,y1,x2,y2)) return ;
    if(tr[k].de) pushdown(k);
    if(in1(k,x1,y1,x2,y2)) tr[k].c=c;
    int l=tr[k].l,r=tr[k].r;
    if(l&&tr[l].de!=c) insert(tr[k].l,x1,y1,x2,y2,c);
    if(r&&tr[r].de!=c) insert(tr[k].r,x1,y1,x2,y2,c);
}
inline int query(int k,int flag){
    if(now==tr[k]) return tr[k].c;
    if(tr[k].de) pushdown(k);
    if(now[flag]==tr[k][flag]){
        if(now[flag^1]<tr[k][flag^1]) return query(tr[k].l,flag^1);
        else return query(tr[k].r,flag^1);
    }
    else if(now[flag]<tr[k][flag]) return query(tr[k].l,flag^1);
    else return query(tr[k].r,flag^1);
}
int main(){
    T=in();
    while(T--){
        tot=dfsn=0;
        memset(point,0,sizeof(point));
        int i,x,j,y,z,ans=0;
        n=in();m=in();m=in();
        for(i=2;i<=n;++i){
            x=in();
            add(x,i);
        }
        dfs(1,0);
        for(i=1;i<=n;++i){
            p[i].c=1;
            p[i].de=0;
            p[i][0]=pos[i];
            p[i][1]=deep[i];
            for(j=0;j<=1;++j)
              p[i].mi[j]=p[i].ma[j]=p[i][j];
        }
        root=build(1,n,0);
        for(i=1;i<=m;++i){
            x=in();y=in();z=in();
            if(z) insert(root,L[x],R[x],deep[x],deep[x]+y,z);
            else{
                now[0]=pos[x];
                now[1]=deep[x];
                int c=query(root,0);
                ans=(ans+(int)(((LL)c*(LL)i)%Mod))%Mod;
            }
        }
        printf("%d\n",ans);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值