[BZOJ4154/Ipsc2015]Generating Synergy

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个操作,\(y_i\)为本次询问的答案(若本次操作是一个修改则\(y_i\)为0),令\(z_i=i*y_i\),请输出\(z_1+z_2+...+z_q\)\(10^9+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,所以答案为\(1*1+2*0+3*3+4*0+5*3+6*0+7*1=32\).
数据范围:
对于100%的数据\(T<\leqslant6,n,m,C\leqslant10^5\),
\(1\leqslant a\leqslant n,0\leqslant l\leqslant n,0\leqslant c\leqslant C\)


对每个点求出dfs序\(L_i,R_i\),和深度\(d_i\),然后每个点映射为平面上的\((L_i,d_i)\)的一个点,每次修改相当于对\(L_i\leqslant L_x\leqslant R_i,d_i\leqslant d_x\leqslant d_i+l\)\(x\)染色,这个可以转化为平面上的矩阵操作

我们建立一棵KD-Tree,支持打区间覆盖标记即可

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
    int x=0,f=1; char ch=gc();
    for (;ch<'0'||ch>'9';ch=gc())   if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0';
    return x*f;
}
inline int read(){
    int x=0,f=1; char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<3)+(x<<1)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x<0)    putchar('-'),x=-x;
    if (x>9)    print(x/10);
    putchar(x%10+'0');
}
const int N=1e5,Mod=1e9+7;
int pre[(N<<1)+10],now[N+10],child[(N<<1)+10];
int deep[N+10],dfn[N+10],size[N+10],pos[N+10];//pos记录i在KD-Tree中的编号
int n,c,q,Time,tot,T;
void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}
void insert(int x,int y){join(x,y),join(y,x);}
void dfs(int x,int fa){
    deep[x]=deep[fa]+1,dfn[x]=++Time,size[x]=1;
    for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
        if (son==fa)    continue;
        dfs(son,x);
        size[x]+=size[son];
    }
}
struct S1{
    #define ls(x) tree[x].ls
    #define rs(x) tree[x].rs
    struct node{
        int v[2],Max[2],Min[2];
        int Lazy,val,ls,rs,ID,fa;
        bool operator <(const node &tis)const{return v[T]<tis.v[T];}
    }tree[N+10];
    int root,L[2],R[2];
    void Add(int *a,int v){a[0]=a[1]=v;}
    int build(int l,int r,int type,int fa){
        T=type;
        int mid=(l+r)>>1,p=mid;
        nth_element(tree+l,tree+mid,tree+r+1);
        tree[p].val=1,tree[p].Lazy=0,tree[p].fa=fa;
        tree[p].ls=tree[p].rs=0;
        pos[tree[p].ID]=p;
        if (l<mid)  ls(p)=build(l,mid-1,type^1,p);
        if (r>mid)  rs(p)=build(mid+1,r,type^1,p);
        tree[p].Min[0]=min(tree[p].v[0],min(tree[ls(p)].Min[0],tree[rs(p)].Min[0]));
        tree[p].Min[1]=min(tree[p].v[1],min(tree[ls(p)].Min[1],tree[rs(p)].Min[1]));
        tree[p].Max[0]=max(tree[p].v[0],max(tree[ls(p)].Max[0],tree[rs(p)].Max[0]));
        tree[p].Max[1]=max(tree[p].v[1],max(tree[ls(p)].Max[1],tree[rs(p)].Max[1]));
        return p;
    }
    void init(){
        Add(tree[0].Max,-inf),Add(tree[0].Min,inf);
        for (int i=1;i<=n;i++)  tree[i].v[0]=dfn[i],tree[i].v[1]=deep[i],tree[i].ID=i;
        root=build(1,n,0,0);
    }
    void Add_tag(int p,int v){
        tree[p].val=v;
        tree[p].Lazy=v;
    }
    void pushdown(int p){
        if (!tree[p].Lazy)  return;
        Add_tag(ls(p),tree[p].Lazy);
        Add_tag(rs(p),tree[p].Lazy);
        tree[p].Lazy=0;
    }
    void Modify(int p,int v){
        bool flag=1;
        for (int i=0;i<2;i++)   if (R[i]<tree[p].Min[i]||L[i]>tree[p].Max[i])   return;
        for (int i=0;i<2;i++){
            if (L[i]>tree[p].Min[i]||R[i]<tree[p].Max[i]){
                flag=0;
                break;
            }
        }
        if (flag){
            Add_tag(p,v);
            return;
        }flag=1;
        pushdown(p);
        for (int i=0;i<2;i++){
            if (tree[p].v[i]<L[i]||R[i]<tree[p].v[i]){
                flag=0;
                break;
            }
        }
        if (flag)   tree[p].val=v;
        Modify(ls(p),v);
        Modify(rs(p),v);
    }
    void Modify(int l1,int r1,int l2,int r2,int v){
        L[0]=l1,L[1]=l2,R[0]=r1,R[1]=r2;
        Modify(root,v);
    }
    int Query(int p){//找到其到root的链,一路pushdown即可
        static int stack[N+10]; int top=0,x=p;
        stack[++top]=p;
        while (tree[p].fa)  stack[++top]=tree[p].fa,p=tree[p].fa;
        for (int i=top;i;i--)   pushdown(stack[i]);
        return tree[x].val;
    }
    #undef ls
    #undef rs
}KDT;//KD-Tree
int main(){
    for (int T=read();T;T--){
        n=read(),c=read(),q=read();
        int res=0; Time=0,tot=0;
        memset(now,0,sizeof(now));
        for (int i=2;i<=n;i++)  insert(read(),i);
        dfs(1,0),KDT.init();
        for (int i=1;i<=q;i++){
            int a=read(),l=read(),c=read();
            if (c)  KDT.Modify(dfn[a],dfn[a]+size[a]-1,deep[a],deep[a]+l,c);
            else    res=(1ll*i*KDT.Query(pos[a])+res)%Mod;
        }
        printf("%d\n",res);
    }
    return 0;
}

转载于:https://www.cnblogs.com/Wolfycz/p/10269082.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值