BNU A Simple Tree Problem 线段树

A Simple Tree Problem
Given a rooted tree, each node has a boolean (0 or 1) labeled on it. Initially, all the labels are 0.
We define this kind of operation: given a subtree, negate all its labels.
And we want to query the numbers of 1's of a subtree.
Input
Multiple test cases.
First line, two integer N and M, denoting the numbers of nodes and numbers of operations and queries.(1<=N<=100000, 1<=M<=10000)
Then a line with N-1 integers, denoting the parent of node 2..N. Root is node 1.
Then M lines, each line are in the format "o node" or "q node", denoting we want to operate or query on the subtree with root of a certain node.
Output
For each query, output an integer in a line.
Output a blank line after each test case.
Sample Input
3 2
1 1
o 2
q 1
Sample Output
1

题意:有几组操作,s[0]=='o'时改变该子树的所有值,使之和原来的值相反,s[0]=='q'时问该子树上有几个点为1
思路:dfs+线段树,这题跟poj3321 差不多
一直WA了一个早上,只因为把初始化放错位置了

代码:
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#define lson l,mid,num<<1
#define rson mid+1,r,num<<1|1
using namespace std;
const int M=100050;
struct node
{
    int v;
    int next;
} edge[M*2];
int sum[M*4],cnt[M*4],head[M];
int low[M],high[M],vis[M];
int cc,e,n,m;
void init()
{
    memset(vis,0,sizeof(vis));
    memset(head,-1,sizeof(head));
    memset(low,0,sizeof(low));
    memset(high,0,sizeof(high));
    cc=e=0;
}
void addEdge(int u,int v)
{
    edge[e].v=v;
    edge[e].next=head[u];
    head[u]=e++;
}
void dfs(int u)
{
    low[u]=++cc;
    vis[u]=1;
    for(int k =head[u]; k!=-1; k=edge[k].next)
    {
        if(!vis[edge[k].v])
            dfs(edge[k].v);
    }
    high[u]=cc;
}
void down(int num,int mm)
{
    if(cnt[num]%2!=0)
    {
        cnt[num<<1]+= cnt[num];
        cnt[num<<1|1]+=cnt[num];
        sum[num<<1] = (mm-(mm>>1))-sum[num<<1];
        sum[num<<1|1] =(mm>>1)-sum[num<<1|1];
        cnt[num]=0;
    }
}
void up(int num)
{
    sum[num] = sum[num<<1] + sum[num<<1|1];
}
void build(int l,int r,int num)
{
    //必须写外面,真是,WA了无数次
    sum[num]=0;
    cnt[num]=0;
    if(l==r)
    {
   	//sum[num]=0;
    	//cnt[num]=0;
return; } int mid = (l+r)>>1; build(lson); build(rson);}void update(int L,int R ,int l, int r ,int num){ if(L<=l && r <=R ) { cnt[num]++; sum[num]=r-l+1-sum[num]; return; } down(num,r-l+1); int mid = (l+r)>>1; if(L <= mid)update(L,R,lson); if(R > mid)update(L,R,rson); up(num);}int query(int L,int R,int l,int r,int num){ if(L <= l && r <= R) { return sum[num]; } down(num,r-l+1); int ret=0; int mid = (l+r)>>1; if(L <= mid ) ret += query(L,R,lson); if(R > mid)ret += query(L,R,rson); return ret;}int main(){ while(scanf("%d%d",&n,&m)!=EOF) { init(); int u; for(int i=2; i<=n; i++) { scanf("%d",&u); addEdge(u,i); addEdge(i,u); } dfs(1); build(1,n,1); char s[2]; int nod; for(int i=1; i<=m; i++) { scanf("%s%d",s,&nod); if(s[0]=='o') { update(low[nod],high[nod],1,n,1); } else if(s[0]=='q') { printf("%d\n",query(low[nod],high[nod],1,n,1)); } } printf("\n"); } return 0;}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值