Educational Codeforces Round 6 E. New Year Tree(DFS序+线段树)

来源:互联网 发布:自挂东南枝网络歌曲 编辑:程序博客网 时间:2024/05/23 10:13

题意:给你一棵树,编号1~n,告诉你根结点是1。 每次有两个操作:

1,将以v为根的子树的结点全部染成颜色c

2,问以v为根的紫书的结点的颜色种类。

思路:如果这是一条线段的话, 那么这就是线段树的区间更新问题,而现在是一棵树。

因为告诉了根结点是1, 那么这棵树的任意一个结点的子树就是确定的, 所以我们可以用DFS的先序遍历,将所有结点重新编号,因为先序遍历的话, 任意一个结点和其子树的编号就是一条连续的线段了,在这其中维护每个结点的新编号, 和这个结点的子树中的最大编号即可。

然后就是线段树区间更新了, 由于颜色数最大60, 用long long通过位运算的 | 操作就行了, 注意对1左移的时候应该先将1转成long long再进行操作。

#include <set>#include <map>#include <stack>#include <queue>#include <deque>#include <cmath>#include <vector>#include <string>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define L(i) i<<1#define R(i) i<<1|1#define INF  0x3f3f3f3f#define pi acos(-1.0)#define eps 1e-9#define maxn 1000100#define MOD 1000000007struct Edge{    int to,next;}edge[maxn];int n,m,tot,pos,num[maxn],mp[maxn];int head[maxn],tmp[maxn],a[maxn];void init(){    tot = 0;    memset(head,-1,sizeof(head));}void add_edge(int u,int v){    edge[tot].to = v;    edge[tot].next = head[u];    head[u] = tot++;}void dfs(int u,int pre){    num[u] = 1;    tmp[u] = pos;    mp[pos++] = u;    for(int i = head[u]; i != -1; i = edge[i].next)    {        int v = edge[i].to;        if(v == pre)            continue;        dfs(v,u);        num[u] += num[v];    }}struct node{    int l,r;    long long sum,lazy;}tree[maxn*4];void pushup(int pos){    tree[pos].sum = tree[pos<<1].sum | tree[pos<<1|1].sum;}void pushdown(int pos){    if(tree[pos].lazy == 0)        return;    tree[pos<<1].sum = tree[pos].sum;    tree[pos<<1|1].sum = tree[pos].sum;    tree[pos<<1].lazy = 1;    tree[pos<<1|1].lazy = 1;    tree[pos].lazy = 0;}void build(int l,int r,int pos){    tree[pos].l = l;    tree[pos].r = r;    tree[pos].sum = 0;    tree[pos].lazy = 0;    if(l == r)    {        tree[pos].sum = 1ll<<(a[mp[l]]-1);        return;    }    int mid = (l+r)>>1;    build(l,mid,pos<<1);    build(mid+1,r,pos<<1|1);    pushup(pos);}                                                   //建树                                                  //查询操作void update(int l,int r,int pos,long long add){    if(tree[pos].l == l && tree[pos].r == r)    {        tree[pos].sum = 1ll<<(add-1);        tree[pos].lazy = 1;        return ;    }    pushdown(pos);    int mid = (tree[pos].l + tree[pos].r) >> 1;    if(r <= mid)        update(l,r,pos<<1,add);    else if(l > mid)        update(l,r,pos<<1|1,add);    else    {        update(l,mid,pos<<1,add);        update(mid+1,r,pos<<1|1,add);    }    pushup(pos);}                                         //自上而下更新节点long long query(int l,int r,int pos){    if(l == tree[pos].l && r == tree[pos].r)        return tree[pos].sum;    pushdown(pos);    int mid = (tree[pos].l+tree[pos].r)>>1;    if(r <= mid)        return query(l,r,pos<<1);    else if(l > mid)        return query(l,r,pos<<1|1);    else        return query(l,mid,pos<<1) | query(mid+1,r,pos<<1|1);}int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    int t,C = 1;    //scanf("%d",&t);    while(scanf("%d%d",&n,&m) != EOF)    {        init();        pos = 1;        memset(num,0,sizeof(num));        for(int i = 1; i <= n; i++)            scanf("%d",&a[i]);        for(int i = 0; i < n-1; i++)        {            int x,y;            scanf("%d%d",&x,&y);            add_edge(x,y);            add_edge(y,x);        }        dfs(1,-1);        build(1,n,1);        for(int i = 0; i < m; i++)        {            int x;            scanf("%d",&x);            if(x == 1)            {                int k,c;                scanf("%d%d",&k,&c);                update(tmp[k],tmp[k]+num[k]-1,1,c);            }            else            {                int k;                scanf("%d",&k);                long long cnt = query(tmp[k],tmp[k]+num[k]-1,1);                int ans = 0;                while(cnt)                {                    if(cnt & 1)                        ans++;                    cnt >>= 1;                }                printf("%d\n",ans);            }        }    }    return 0;}



0 0