「USACO 2019.12 Platinum」Bessie‘s Snow Cow (Set + 树状数组)

Description
农场下雪啦!Bessie 和往年开冬一样在堆雪牛。她之前是个写实派,总是想把他的雪牛堆得和个真牛一样。但今年不一样,受到来自东方的神秘力量的影响,他想来点抽象艺术,因此他想堆成一棵树的样子。这棵树由 个雪球, 根树枝构成,每根树枝连接两个雪球,并且每两个雪球之间路径唯一。

Bessie 要给他的雪牛来点细节。因此他给其中一个雪球加了个鼻子,来表示这是他那抽象的牛的头,并且把它称作雪球 。为了让雪牛更好看,他还要给某些雪球来点不同的颜色。于是,他用旧牛奶桶装满了颜料泼到雪牛上。这些颜料分别被编号为 ,且每种颜色都无限量供应。

当 Bessie 把一桶颜料泼到一个雪球上时,这个雪球子树上的所有雪球也会被染色(我们称雪球 在雪球 的子树里当且仅当雪球 处在雪球 到雪球 的路径上)。Bessie 有着精确的泼颜料技术,因此在泼完一种颜料后,一个雪球上之前被染过的所有颜色依然清晰可见。例如,一个雪球之前显现出来颜色 ,然后 Bessie 把装有 号颜色的牛奶桶泼上去,那么这个雪球将显现出来颜色 。 在泼了几桶颜料以后,Bessie 可能想要了解它的雪牛有多五彩斑斓。令雪球 的『颜色丰富度』为这个雪球被染上的不同颜色总数 ,当 Bessie 想了解雪球 的相关信息时,你应该回答他雪球 的子树中所有的雪球的颜色丰富度之和。

救救孩子吧!

Input
第一行, N N N 和询问数 Q Q Q

接下来 N − 1 N-1 N1 行每行两个用空格隔开的数 a a a b b b,表示雪球 a a a b b b中间有一根树枝相连。

最后 q q q行每行一个请求,格式及对应含义如下:

1   x   c 1~x~c 1 x c(修改):表示 Bessie 把一桶装有颜色 c c c 的颜料泼到雪球 x x x ,使得其子树上所有雪球被染色。
2   x 2~x 2 x(询问):询问雪球 x x x 的子树的颜色丰富度之和。

Output
对于每个询问,输出所询问子树的颜色丰富度之和。为了防止溢出,你需要使用 64 位整数。

Examples

Input
5 18
1 2
1 3
3 4
3 5
1 4 1
2 1
2 2
2 3
2 4
2 5
1 5 1
2 1
2 2
2 3
2 4
2 5
1 1 1
2 1
2 2
2 3
2 4
2 5
Output
1
0
1
1
0
2
0
2
1
1
5
1
3
1
1

Note
1 ≤ N , Q , c ≤ 1 0 5 , 1 ≤ a , b , x ≤ N 1 \leq N, Q, c \leq 10^5, 1 \leq a,b,x \leq N 1N,Q,c105,1a,b,xN
Souce
LibreOJ 3227
USACO 2019 December Contest, Platinum

Solution
对每种颜色维护一个Set,存放已经染上这种颜色的子树区间
如果只有对子树区间的修改,容易发现每次修改的区间要么相互包含,要么就没有交集
所以修改区间[L,R] 时,在对应颜色的Set中将包含于其的区间的贡献删除,再添加上该区间的贡献
套上树状数组区间修改/查询

Code

#include <bits/stdc++.h>
#define P pair<int,int>
using namespace std;
const int maxn = 2e5 + 7;
inline int lowbit(int x){return x & (-x);}
int n;
ll bit1[maxn<<1],bit2[maxn<<1];

void modify(ll bit[] ,int pos,int k){
    while(pos <= n) bit[pos] += k, pos += lowbit(pos);
}

ll query(ll bit[], int pos){
    ll res = 0;
    while(pos) res += bit[pos], pos -= lowbit(pos);
    return res;
}

void modify(int l,int r,int k){
    modify(bit1,l,k); modify(bit1,r+1,-k);
    modify(bit2,l,k*l); modify(bit2,r+1,-k*(r+1));
}

ll query(int l,int r){
    return (query(bit1,r) * (r+1) - query(bit2,r)) - (query(bit1,l-1)*l - query(bit2,l-1));
}

int ecnt,head[maxn<<1];
struct Edge{
    int v,next;
}e[maxn << 1];
void add(int u,int v){
    e[++ecnt] = (Edge) {v,head[u]}, head[u] = ecnt;
    e[++ecnt] = (Edge) {u,head[v]}, head[v] = ecnt;
}
int cnt,dfn[maxn],low[maxn];

void dfs(int u,int fa){
    dfn[u] = ++cnt;
    for(int i = head[u];i;i = e[i].next){
        int v = e[i].v;if(v == fa) continue;
        dfs(v,u);
    }
    low[u] = cnt;
}

set<P>S[maxn];
int main(){
    int q;
    scanf("%d%d",&n,&q);
    for(int i = 1, u,v;i < n;++i){
        scanf("%d%d",&u,&v);add(u,v);
    }
    dfs(1,-1);
    for(int i = 1,u,c;i <= q;++i){
        int op;scanf("%d",&op);
        if(op == 1){
            scanf("%d%d",&u,&c);
            set<P>::iterator it = S[c].lower_bound({dfn[u],0});
            if(it != S[c].end() && (*it).sec <= dfn[u]) continue;
            while(it != S[c].end() && (*it).fir <= low[u]){
                modify((*it).sec, (*it).fir, -1);
                S[c].erase(it++);
            }
            modify(dfn[u], low[u], 1);
            S[c].insert({low[u], dfn[u]});
        } else{
            scanf("%d",&u);printf("%lld\n", query(dfn[u],low[u]));
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值