5093 dfs序+线段树 ,边转点

本文探讨了一种特定的树形数据结构问题——寻找所有路径异或和为1的路径数量。通过深度优先搜索(DFS)算法遍历树结构,并使用线段树进行区间更新查询,最终解决了该问题。文章提供了两种实现方案的源代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给你一个树,问你树的路径异或和为1的路径树。

WA了N次,后来dfs换成了另一种方式过了,再后来发现是自己忘记了rk数组,还是不够熟练,理解也不够深,后来换成自己的方式过了, 附上两个代码。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <iostream>
#include <map>
#include <string>
using namespace std;
typedef long long ll;
const int N=30005;
struct node
{
    int to,nxt,w;
}edge[N*2];
map<string,int> ma;
int in[N],out[N];
int head[N],cnt,tim,a[N];
pair<int,int> q[N];
void add(int u,int v ,int w)
{
    edge[++cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].nxt=head[u];
    head[u]=cnt;
}
void dfs(int u,int pre,int w)
{
    tim++;
    in[u]=tim;
    a[tim]=w;
    for(int i=head[u];~i;i=edge[i].nxt)
    {
        int v=edge[i].to;
        if(v!=pre)
            dfs(v,u,w^edge[i].w);
    }
    out[u]=tim;
}
#define ls l,mid,rt<<1
#define rs mid+1,r,rt<<1|1
int sum[N<<2],lazy[N<<2];
void up(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void down(int rt,int l,int r)
{
    if(lazy[rt])
    {
        lazy[rt<<1]^=1;
        lazy[rt<<1|1]^=1;
        int mid=(l+r)>>1;
        sum[rt<<1]=mid-l+1-sum[rt<<1];
        sum[rt<<1|1]=r-mid-sum[rt<<1|1];
        lazy[rt]=0;
    }
}
void build(int l,int r,int rt)
{
    lazy[rt]=0;
    if(l==r)
    {
        sum[rt]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(ls);
    build(rs);
    up(rt);
}
void update(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        lazy[rt]^=1;
        sum[rt]=r-l+1-sum[rt];
        return;
    }
    int mid=(l+r)>>1;
    down(rt,l,r);
    if(mid>=L) update(L,R,ls);
    if(mid<R) update(L,R,rs);
    up(rt);
}
int main()
{
    //    freopen("/Users/wang/Desktop/text专用/in.txt","r",stdin);
    //    freopen("/Users/wang/Desktop/text专用/out.txt","w",stdout);
    int t;
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++)
    {
        ma.clear();
        memset(head,-1,sizeof(head));
        int n; char u[30],v[30];
        int w ;cnt=0,tim=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",u);
            ma[(string)u]=i;
        }
        for(int i=1;i<n;i++)
        {
            scanf("%s%s%d",u,v,&w);
            int id1=ma[(string)u],id2=ma[(string)v];
            add(id1,id2,w);
            add(id2,id1,w);
            q[i]=make_pair(id1,id2);
        }
        dfs(1,0,0);
        build(2,n,1);
        printf("Case #%d:\n",cas);
        int qq;
        scanf("%d",&qq);
        while(qq--)
        {
            char cmd[5];
            scanf("%s",cmd);
            if(cmd[0]=='Q')
                printf("%d\n", sum[1]*(n-sum[1])*2);
            else if(cmd[0]=='M')
            {
                int pos;
                scanf("%d",&pos);
                int uu=q[pos].first,vv=q[pos].second;
                if(in[uu]>in[vv]) swap(uu,vv);
                update(in[vv],out[vv],2,n,1);
            }
        }
    }
}
//11
//11
//a
//b
//c
//d
//e
//f
//g
//h
//i
//j
//k
//a b 1
//a c 1
//b d 1
//b e 0
//e h 1
//h i 0
//i j 1
//j k 0
//c f 0
//c g 1
//10
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <iostream>
#include <map>
#include <string>
using namespace std;
typedef long long ll;
const int N=30005;
struct node
{
    int to,nxt,w;
}edge[N*2];
map<string,int> ma;
int in[N],out[N];
int rk[N];
int head[N],cnt,tim,a[N];
pair<int,int> q[N];
void add(int u,int v ,int w)
{
    edge[++cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].nxt=head[u];
    head[u]=cnt;
}
void dfs(int u,int pre)
{
    tim++;
    in[u]=tim;
    rk[tim]=u;
    for(int i=head[u];~i;i=edge[i].nxt)
    {
        int v=edge[i].to;
        if(v!=pre)
        {
            a[v]=a[u]^edge[i].w;
            dfs(v,u);
        }
    }
    out[u]=tim;
}
#define ls l,mid,rt<<1
#define rs mid+1,r,rt<<1|1
int sum[N<<2],lazy[N<<2];
void up(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void down(int rt,int l,int r)
{
    if(lazy[rt])
    {
        lazy[rt<<1]^=1;
        lazy[rt<<1|1]^=1;
        int mid=(l+r)>>1;
        sum[rt<<1]=mid-l+1-sum[rt<<1];
        sum[rt<<1|1]=r-mid-sum[rt<<1|1];
        lazy[rt]=0;
    }
}
void build(int l,int r,int rt)
{
    lazy[rt]=0;
    if(l==r)
    {
        sum[rt]=a[rk[l]];
        return;
    }
    int mid=(l+r)>>1;
    build(ls);
    build(rs);
    up(rt);
}
void update(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        lazy[rt]^=1;
        sum[rt]=r-l+1-sum[rt];
        return;
    }
    int mid=(l+r)>>1;
    down(rt,l,r);
    if(mid>=L) update(L,R,ls);
    if(mid<R) update(L,R,rs);
    up(rt);
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++)
    {
        ma.clear();
        memset(head,-1,sizeof(head));
        int n; char u[20],v[20];
        int w ;cnt=0,tim=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",u);
            ma[(string)u]=i;
        }
        for(int i=1;i<n;i++)
        {
            scanf("%s%s%d",u,v,&w);
            int id1=ma[(string)u],id2=ma[(string)v];
            add(id1,id2,w);
            add(id2,id1,w);
            q[i]=make_pair(id1,id2);
        }
        a[1]=0;
        dfs(1,0);
        build(2,n,1);
        for(int i=1;i<n;i++)
        {
            int uu=q[i].first,vv=q[i].second;
            if(in[uu]<in[vv])
                q[i].first=vv;
            else q[i].first=uu;
        }
        printf("Case #%d:\n",cas);
        int qq;
        scanf("%d",&qq);
        while(qq--)
        {
            char cmd[5];
            scanf("%s",cmd);
            if(cmd[0]=='Q')
                printf("%d\n", sum[1]*(n-sum[1])*2);
            else if(cmd[0]=='M')
            {
                int pos;
                scanf("%d",&pos);
                int uu=q[pos].first;
                update(in[uu],out[uu],2,n,1);
            }
        }
    }
}
//11
//11
//a
//b
//c
//d
//e
//f
//g
//h
//i
//j
//k
//a b 1
//a c 1
//b d 1
//b e 0
//e h 1
//h i 0
//i j 1
//j k 0
//c f 0
//c g 1
//10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值