Gym - 101615D Rainbow Roads (dfs序,差分)

题目链接

题意:给你一颗无向树,树上的每条边都有一种颜色,如果以一个点为起点的所有的路径上相邻两条边的颜色总是不相同,那么这个点被称为“好点”。求这棵树上所有的好点。

解法:假设节点u和节点v均与节点w相邻,且e(w,u)与e(w,v)颜色相同,那么要分两种情况:

(1)u与v不存在祖先与后代的关系,那么这两个结点所在的内子树上的点都不是好点,都要剪掉。

(2)u是v的祖先,那么v的内子树与u的外子树及u的内子树中除w的内子树的部分都要剪掉。

这样问题转化成了区间修改查询问题。由于dfs序对子树的处理是比较优秀的,[bg[u],ed[u]]上所有的点构成u的内子树,剩下的区间加上bg[u]构成u的外子树,可以用差分的思想在结点的dfs序上打标记,最后没被标记过的点就是好点。

我是用树状数组处理的,也可以直接在原序列上打标记,最后从头到尾扫一遍

#include
using namespace std;
typedef long long ll;
const int N=5e4+10;
int head[N],to[N<<1],nxt[N<<1],col[N<<1],nEdge;
int bg[N],ed[N],cntcol[N],nnode;
int c[N];
vector ans;

int lowbit(int x) {return x&-x;}
void add(int u,int x)
{
    while(u1)
        {
            int v=to[e];
            add(bg[v],1),add(ed[v]+1,-1);
            if(v==fa)add(1,1),add(bg[v]+1,-1),add(ed[v]+1,1),add(bg[u],-1),add(ed[u]+1,1);
        }
    }
    for(int e=head[u]; ~e; e=nxt[e])cntcol[col[e]]=0;
    for(int e=head[u]; ~e; e=nxt[e])
    {
        int v=to[e];
        if(v==fa)continue;
        dfs2(v,u,col[e]);
    }
}

int main()
{
    memset(head,-1,sizeof head);
    memset(cntcol,0,sizeof cntcol);
    nEdge=nnode=0;
    int n;
    scanf("%d",&n);
    for(int i=1; i

 

你可能感兴趣的:(差分,dfs序)