dfs+线段树(hdu5039 - Hilarity)

Hilarity

Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 461    Accepted Submission(s): 125


Problem Description
After June 1st, elementary students of Ted Land are still celebrating "The Sacred Day of Elementary Students”. They go to the streets and do some elementary students stuff. So we call them "elementary students". There are N cities in Ted Land. But for simplicity, the mayor Matt only built N - 1 roads so that all cities can reach each other. Some of the roads are occupied by the "elementary students". They will put an celebration hat on everyone who goes through the road without one. But if someone goes through the road with a celebration hat on his head, "elementary students" will steal the hat for no reason. Since Matt doesn’t have a celebration hat, he wants to know how many different paths in his land that he can end up with a hat. Two paths are considered to be different if and only if they have different start city or end city. As the counsellor of the mayor Matt, you have to answer this question for him. The celebration elementary students are not stable: sometimes a new crowd of elementary students go to an empty road; sometimes the elementary students on a road will go back home and remain the road empty. Matt will send you the monitor about the change of elementary students on road and ask you the question above. You will be fired if you answer wrong.
 

Input
The first line of the input contains an integer T, denoting the number of testcases. Then T test cases follow.

For each test case, the first line contains N (1<=N<=30000) describing the number of cities.

Then N lines follow. The ith line of these contains the name of the ith city, it’s a string containing only letters and will not be longer than 10.

The following N - 1 lines indicate the N - 1 edges between cities. Each of these lines will contain two strings for the cities’ name and a integer for the initial status of the edge (0 for empty, 1 for crowded).

Then an integer M (1<=M<=60000) describes the number of queries. There are two kinds of query:

● "M i" means the status changing of the ith (starting from 1) road (0 to 1, 1 to 0);
● "Q" means that Matt asks you the number of different paths.
 

Output
For each test case, first output one line “Case #x:”, where x is the case number (starting from 1).

Then for each “Q” in input, output a line with the answer.
 

Sample Input
  
  
1 5 a b c d e a b 1 b c 0 c d 1 d e 1 7 Q M 1 Q M 3 Q M 4 Q
 

Sample Output
  
  
Case #1: 12 8 8 0


题意:n个点的树,每条边有两种权值0,1,想在有两种操作,M i表示将的i条边的值取反,Q操作表示询问书中有多少节点对(u,v)使得u->v路径上1的格式为奇数个。

思路:u->v的路径可以由u->1,1->v两段拼接起来(有可能这两段有重叠的地方,但是重叠的地方计算了两次,所以对结果并没有影响)那么问题就转化成了有多少个节点到1的路径上有奇数个1(假设个数为x),那么剩下的节点(除了根节点1)就是到1有偶数个1的(假设为y),那么答案就是x*y+z(这个是不需要拼接的,距离根节点的距离直接为奇数的),所以先dfs将边排序,并且记录下节点u到根节点的路径上1的奇偶(xor就可以了),然后就是线段树更新,查询了

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=30010;
int N,M,n,tot;
map<string,int> mp;
int head[maxn];
int a[maxn];
struct node
{
    int v,next,w;
}edge[maxn*2];
int in[maxn],out[maxn];
void init()
{
    tot=n=0;
    memset(head,-1,sizeof(head));
}
void add_edge(int u,int v,int w)
{
    edge[tot].v=v;
    edge[tot].next=head[u];
    edge[tot].w=w;
    head[u]=tot++;
}
void dfs(int u,int fa,int x)
{
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==fa)continue;
        in[i/2]=++n;
        a[n]=x^edge[i].w;
        dfs(v,u,x^edge[i].w);
        out[i/2]=n;
    }
}
struct IntervalTree
{
    int sum[maxn<<2];
    int setv[maxn<<2];
    void build(int o,int l,int r)
    {
        sum[o]=0;
        setv[o]=0;
        if(l==r)
        {
            sum[o]=a[l];
            return;
        }
        int mid=(l+r)>>1;
        build(o<<1,l,mid);
        build(o<<1|1,mid+1,r);
        pushup(o);
    }
    void pushup(int o)
    {
        sum[o]=sum[o<<1]+sum[o<<1|1];
    }
    void update(int o,int l,int r,int q1,int q2)
    {
        if(q1<=l&&r<=q2)
        {
            setv[o]^=1;
            sum[o]=r-l+1-sum[o];
            return;
        }
        pushdown(o,l,r);
        int mid=(l+r)>>1;
        if(q1<=mid)update(o<<1,l,mid,q1,q2);
        if(q2>mid)update(o<<1|1,mid+1,r,q1,q2);
        pushup(o);
    }
    void pushdown(int o,int l,int r)
    {
        if(setv[o])
        {
            int mid=(l+r)>>1;
            setv[o<<1]^=1;
            setv[o<<1|1]^=1;
            sum[o<<1]=mid-l+1-sum[o<<1];
            sum[o<<1|1]=r-mid-sum[o<<1|1];
            setv[o]=0;
        }
    }
}tree;
int main()
{
    int T,cas=1;
    string name,name1;
    int u,v,x;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&N);
        mp.clear();
        init();
        for(int i=1;i<=N;i++)
        {
            cin>>name;
            mp[name]=i;
        }
        for(int i=1;i<N;i++)
        {
            cin>>name>>name1;
            scanf("%d",&x);
            u=mp[name],v=mp[name1];
            add_edge(u,v,x);
            add_edge(v,u,x);
        }
        dfs(1,0,0);
        tree.build(1,1,n);
        scanf("%d",&M);
        char op[5];
        printf("Case #%d:\n",cas++);
        while(M--)
        {
            scanf("%s",op);
            if(op[0]=='Q')
                printf("%d\n",tree.sum[1]*(N-tree.sum[1])*2);
            else
            {
                scanf("%d",&x);
                x--;
                tree.update(1,1,n,in[x],out[x]);
            }
        }
    }
    return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值