HDU 1540 线段树单点查询+dfs建立区间大小(时间戳)+分析为什么查询左子树

During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally speaking, villages connected by tunnels lay in a line. Except the two at the ends, every village was directly connected with two neighboring ones. 

Frequently the invaders launched attack on some of the villages and destroyed the parts of tunnels in them. The Eighth Route Army commanders requested the latest connection state of the tunnels and villages. If some villages are severely isolated, restoration of connection must be done immediately! 

Input

The first line of the input contains two positive integers n and m (n, m ≤ 50,000) indicating the number of villages and events. Each of the next m lines describes an event. 

There are three different events described in different format shown below: 

D x: The x-th village was destroyed. 

Q x: The Army commands requested the number of villages that x-th village was directly or indirectly connected with including itself. 

R: The village destroyed last was rebuilt. 

Output

Output the answer to each of the Army commanders’ request in order on a separate line. 

Sample Input

7 9
D 3
D 6
D 5
Q 4
Q 5
R
Q 4
R
Q 4

Sample Output

1
0
2
4

题意:给定点的上下级关系,规定如果给i分配任务a,那么他的所有下属。都停下手上的工作,开始做a。

          操作 T x y 分配x任务y,C x询问x的当前任务;

#include<iostream>
#include<stack>
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
#define lson id<<1
#define rson id<<1|1
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Abs(a) (a)>=0?(a):(-a)
const int N = 5e4+10;
const int INF = 0x3f3f3f3f;
vector<int> boss[N];
vector<int> subordinate[N];
struct node{
    int l,r,val;
}a[N<<2];
int cnt;
int L[N];
int R[N];
void dfs(int v){
    cnt++;
    L[v]=cnt;
    for(int i=0;i<boss[v].size();i++)
        dfs(boss[v][i]);
    R[v]=cnt;
    return ;
}
void pushdown(int id){//只能是pushdown,不能够pushup,这道题的特殊行决定的
    if(a[id].val!=-1){
        a[lson].val=a[rson].val=a[id].val;
        a[id].val=-1;
    }
}
void build(int id,int l,int r){
    a[id].l=l;
    a[id].r=r;
    a[id].val=-1;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
}
void update(int id,int l,int r,int val){
    if(a[id].l==l&&a[id].r==r){
    a[id].val=val;
    return ;
     }

    pushdown(id);
    int mid=(a[id].l+a[id].r)>>1;

    if(r<=mid) update(lson,l,r,val);
    else if(l>mid) update(rson,l,r,val);
    else{
        update(lson,l,mid,val);
        update(rson,mid+1,r,val);
    }
}
int query(int id,int p){
    if(a[id].l==a[id].r)
        return a[id].val;
    pushdown(id);//在本题目中查询操作就像是查询lazy标记,所以要在查询函数中调用pushdown函数
    int mid=(a[id].l+a[id].r)>>1;//否则lazy标记,也就是a[id].val没有办法下压,那么答案就有可能是-1
    if(p<=mid) return query(lson,p);
    else  return query(rson,p);
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
    int t;
    scanf("%d",&t);
    int T=1;
    while(t--){
        printf("Case #%d:\n",T++);
        int n;
        cnt=0;
        scanf("%d",&n);
        rep(i,0,n) if(boss[i].size()) boss[i].clear();
        rep(i,0,n) if(subordinate[i].size()) subordinate[i].clear();

        rep(i,1,n-1){int u,v;
        scanf("%d%d",&u,&v);
        subordinate[u].push_back(v);
        boss[v].push_back(u);
        }

        rep(i,1,n)
        if(subordinate[i].size()==0){
            dfs(i);
            break;
        }

        build(1,1,cnt);

        int q=0;
        scanf("%d",&q);
        char str[10];
        while(q--){
            scanf("%s",str);
            if(str[0]=='T'){int x,y;
            scanf("%d%d",&x,&y);
            update(1,L[x],R[x],y);
            }else{int x;
            scanf("%d",&x);
            printf("%d\n",query(1,L[x]));//不清楚为什么单点查询的时候要查询左边,有大神可以帮忙解决一下感激不尽
            }
        }
//        printf("%d\n",a[6].val);
    }
    return 0;
}

对于上面的我留下的疑问我费了一番bug,在这里跟大家分享一下:

首先是建树,这样说不太准确,应该是dfs的过程中说一下,拿样例来说经过dfs以后,建立的区间大小包含关系是这样的:

                                        {2} [1,5]

                      {3}[2,4]                   {5}[5,5]

       {4}[3,3]             {1}[4,4]

{}里面代表是几号;[a,b]代表是该点所能覆盖的区间

通过上面的区间的关系,我们能够发现没有区间[1,1]  [2,2],这就是建立这种相应的关系的巧妙的地方

 

下面我给出一组这样的样例

4
T 5 1
C 3
T 4 3
C 2(其他的和题目所给的样例一样)

如果我们查询右边的区间,也就是R[2]的时候(R[x]是代码中的使用,这是执行C 2这一指令),经过上面的代码,查询的时候会取查询5这个区间。并最终落到[5,5]这个区间,但是,但是 [5,5]这个区间在第一次就被赋值为1,但是这四次操着没有关系到2号点的事,但是它却将区间[5,5]的值返回了,很明显是错的;

当我们传的是L[5]的时候,查询的就是区间1,那么最终在pushdown函数的作用下将区间[1,1]的值返回,这就是这一题的一个需要注意的细节
 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值