HDU 6203 ping ping ping lca 线段树成段更新

题目链接:HDU 6203

ping ping ping

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 507    Accepted Submission(s): 128


Problem Description
The structure of the computer room in Northeastern University is pretty miraculous. There are n servers, some servers connect to the gateway whose IP address is 0 directly. All servers are connected with each other by n netting twines. It is said that this structure is favorable for maintaining physical problem of servers.
But because of an unexpected rainstorm, the computer room was destroyed by a terrible thunderclap!
Our maintainer Bittersweet found that many servers were not able to be visited, so he hurried to the computer room to lookup the reason. After several hours, Bittersweet realized that some net gape of servers were broken by thunderclap. However, there were too many servers to find out all the broken net gapes quickly. So he came up with an idea to assess the damaged condition roughly. Bittersweet decided to turn on some servers and ping other servers randomly, then record the unsuccessful pairs of servers.
Now he need a program to analyze the record to confirm what is the minimum number of servers whose net gape was destroyed by thunderclap. Can you help him to complete this work?
 

Input
There are at most 20 test cases.
In each test case, the first line is an integer n (3n104), denoting the number of servers. The IP address of these servers is 1n.
Then follows n lines, each line contains two integers u and v (0u,vn), denoting that the server whose IP address is u is connected with the server whose IP address is v by netting twine initially.
After those, there is one line contains only an integer p (p50000), denoting the number that Bittersweet uses ping.
Then follows p lines, each line contains two integers U and V , denoting when using server U to ping server V, it returned unsuccessful.
 

Output
A single integer x in a line, denoting at least x servers whose net gape were broken.
 

Sample Input
4 1 0 4 2 2 0 3 2 2 1 3 2 1
 

Sample Output
1
 

题意:

已知n+1个点从0到n,构成一棵树,现在有一些对节点ping不通,问最少会有几个节点坏掉。

题目分析:思路参考http://blog.csdn.net/DorMOUSENone/article/details/77929604

树状数组的区间维护没写过,所以节点信息我用线段树来维护。这里我们先预处理出来每一对节点的lca,然后按照lca由大至小排序,然后预处理出来每个点的dfs序in[]和后序的dfs序out[],这样如果点pos的节点坏掉了,其子树上的所有节点u都有in[pos]<in[u]<out[u]<out[pos]。由于每次处理lca深度深的点,所以每次查询u和v有没有被标记过,如果没有说明2个点到最近公共祖先的路径还没有坏,为了让每个坏点达到最大覆盖范围,所以贪心的认定是最近公共祖先的节点坏掉了,同时区间标记整个范围in[]~out[],同理,如果u和v两点任意一点已经被标记了,而它们的lca深度一定比之前的节点小,所以二者显然已经无法ping通。然后计数就好了。

dfs序标记和处理树,然后录入线段树,每次查询区间维护lazy。

//
//  main.cpp
//  HDU 6203 ping ping ping
//
//  Created by teddywang on 2017/09/12.
//  Copyright © 2017年 teddywang. All rights reserved.
//

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=1e5;
const int inf=0x3f3f3f3f;
struct node{
    int x,y,lca;
    friend bool operator < (node a,node b)
    {
        return a.lca>b.lca;
    }
    
}nodes[maxn];
int in[maxn],out[maxn],depth[maxn],order[maxn],tree[maxn];
int s,e,pos1,ans,n,m,cnt,mins,anspos;
bool lazy[maxn];
vector <int> edge[maxn];

void dfs1(int pos,int fa)
{
    int len=edge[pos].size();
    order[++cnt]=pos;
    in[pos]=cnt;
    for(int i=0;i<len;i++)
    {
        if(edge[pos][i]!=fa)
        {
            depth[ edge[pos][i] ]=depth[pos]+1;
            dfs1(edge[pos][i],pos);
            order[++cnt]=pos;
        }
    }
}

void dfs2(int pos,int fa)
{
    int len=edge[pos].size();
    in[pos]=++cnt;
    for(int i=0;i<len;i++)
    {
        if(edge[pos][i]!=fa)
        {
            //in[edge[pos][i]]=++cnt;
            dfs2(edge[pos][i],pos);
        }
    }
    out[pos]=cnt;
}


void pushup1(int rt)
{
    tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
}

void push_down2(int rt)
{
    if(lazy[rt]==1)
        lazy[rt<<1]=lazy[rt<<1|1]=1;
}

void build1(int l,int r,int rt)
{
    if(l==r)
    {
        tree[rt]=depth[order[l]];
        return ;
    }
    int mid=(l+r)>>1;
    build1(l,mid,rt<<1);
    build1(mid+1,r,rt<<1|1);
    pushup1(rt);
}

void update2(int st,int ed,int l,int r,int rt)
{
    if(l>ed||st>r) return;
    if(st<=l&&r<=ed)
    {
        lazy[rt]=1;
        return;
    }
    int mid=(l+r)>>1;
    update2(st,ed,l,mid,rt<<1);
    update2(st,ed,mid+1,r,rt<<1|1);
}

void query1(int st,int ed,int l,int r,int rt)
{
    if(st>r||l>ed) return;
    if(st<=l&&r<=ed)
    {
        if(tree[rt]>mins) return;
        mins=tree[rt];
    }
    if(l==r)
    {
        anspos=l;
        return;
    }
    int mid=(l+r)>>1;
    query1(st,ed,l,mid,rt<<1);
    query1(st,ed,mid+1,r,rt<<1|1);
}

int query2(int st,int ed,int l,int r,int rt)
{
    if(st>r||l>ed) return 0;
    if(l<=st&&ed<=r)
    {
        if(lazy[rt]) return 1;
    }
    if(l==r) return 0;
    push_down2(rt);
    int mid=(l+r)>>1;
    return query2(st,ed,l,mid,rt<<1)||query2(st,ed,mid+1,r,rt<<1|1);
}

int main()
{
    while(~scanf("%d",&n))
    {
        depth[0]=0;cnt=0;
        for(int i=0;i<=n;i++)
            edge[i].clear();
        for(int i=0;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            edge[u].push_back(v);
            edge[v].push_back(u);
        }
        dfs1(0,-1);
        build1(1,cnt,1);
        scanf("%d",&m);
        for(int i=0;i<m;i++)
        {
            int u,v;                                                        
            scanf("%d%d",&u,&v);
            s=in[u],e=in[v],mins=inf;
            if(s>e) swap(s,e);
            query1(s,e,1,cnt,1);
            nodes[i].x=u,nodes[i].y=v;
            nodes[i].lca=order[anspos];
        }
        sort(nodes,nodes+m);
        ans=0,cnt=0;
        dfs2(0,-1);
        memset(lazy,0,sizeof(lazy));
        for(int i=0;i<m;i++)
        {
            s=e=in[nodes[i].x];
            if(!query2(s,e,1,cnt,1))
            {
                s=e=in[nodes[i].y];
                if(!query2(s,e,1,cnt,1))
                {
                    ans++;
                    s=in[nodes[i].lca];
                    e=out[nodes[i].lca];
                    update2(s,e,1,cnt,1);
                }
            }
        }
        printf("%d\n",ans);
    }
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章