Regionals 2013 :: North America - Southeast USA

Regionals 2013 :: North America - Southeast USA

It Takes a Village

  As a Sociologist, you are studying a certain kingdom. This kingdom has a capitol city, several villages,
and roads between them all. Through your sociological studies, you have been able to determine that
there are three separate conditions under which one village will economically affect another village.
Village P will affect village Q if ANY of the following are true:
  1.If there are two completely different paths to get from village P to village Q, with no villages in
common (other than P and Q).
  2.If every path from Q to the capitol goes through P.
  3.If P affects village R and R affects Q.
  The kingdom is starting to build trading posts, to boost the economic health of its villages. When
it builds a trading post, it increases the overall revenue of the village it is placed in, and of all villages
which are affected by that village according to the above rules. Now, the king wants to know the effect
of his new trading posts, so he occasionally asks you to tell him the revenue of a certain village.
Given a sequence of the kings actions, both building trading posts and asking about a certain village,
answer his questions.

Input
There will be several test cases in the input. Each test case will begin with a line with two integers, n (2≤n≤100,000) and k (1≤k≤109), where n is the number of points, and k is the desired maximum distance. On each of the following n lines will be three integers x, y and z (-109≤x,y,z≤109) which are the (x,y,z) coordinates of one point. Within a test case, there will be no duplicate points. Since star systems are generally sparse, it is guaranteed that no more than 100,000 pairs of points will be within k of each other. The input will end with a line with two 0s.
Output
For each test case, output a single integer indicating the number of unique pairs of points that are less than k apart from each other. Output no spaces, and do not separate answers with blank lines.

SampleInput
3 2 4
1 2
3 1
+ 1 1
? 3
+ 2 3
? 3
2 2 4
1 2
2 1
+ 1 1
? 2
+ 2 3
? 1
0 0 0
SampleOutput
1
1
1
4

题目大意:给定一张无向图带环图,不包含自边和重边。定义,

<1>如果PQ两点间存在两条完全不重合路径;

<2>如果Pcapital的路径经过Q,则PQ的影响;

<3>PZ互相影响,ZQ互相影响,则PQ互相影响。

Capital 恒为点1.

多组输入,包括nmq。(n个点,m条边,q次操作)

1 < n < 1e5   ,   1< m < 1e5   , 1 < q < 2e5;

q表示两种操作的数量:

<1>   + K X  K点加权X

<2>   ?  K  查询K点的权和影响它的点的权的总和

1 <= k <= n,1 <= x <= 1000

在政神的指导下,这题应该是双连通分量+数据结构

根据给定的条件<1><2><3>,可以知道,相互影响的点一定是在同一个双连通分量里的,这样我们可以对原图缩点,缩完点之后图转化为一棵以capital为根的树,这时候利用树状数组维护DFS序列。所以,先 tarjan 缩点,然后从capital节点做一遍DFS,记录每个节点入栈和出栈的序列。用树状数组维护节点权值,遇到 + K X,就在点的入栈序列上 +X,在出栈序列+1 –X,查询操作返回节点入栈序列的前缀和。

由于点数是100,000,在原图是一条链的情况下,会RE爆栈,

#pragma comment(linker, "/STACK:102400000,102400000")这是一条C++的扩栈指令,师大的OJ不提供C++编译器,是无法扩栈的。需要用到传说中的汇编扩栈!

上代码:

const int main_stack = 16;

char my_stack[128 << 20];

    __asm__("movl %%esp, (%%eax);\n"::"a"(my_stack):"memory");

__asm__("movl %%eax, %%esp;\n"::"a"(my_stack + sizeof(my_stack) - main_stack):"%esp");

__asm__("movl (%%eax), %%esp;\n"::"a"(my_stack):"%esp");

#include<iostream>

#include<cstdio>

#include<cstring>

#include<stack>

#include<cstdlib>



using namespace std;

const int nMax = 2e5+10;

struct Edge{

    int u,v,nxt;

}edge[nMax<<1],edge_v[nMax<<2];

int g[nMax],g_v[nMax],nume,Nume;

int mark[nMax<<1],s[nMax<<1];

int cor[nMax],low[nMax],dfn[nMax],cnt,bcc;

int in_idx[nMax],out_idx[nMax];

int n,m;

stack<int> st;

inline int Low_bit(int x)

{

    return x&-x;

}

void take_plus(int pos,int x)

{

    while( pos < nMax )

        s[pos]+=x,pos+=Low_bit(pos);

}

int take_sum(int pos)

{

    int ret = 0;

    while( pos )

        ret+=s[pos],pos-=Low_bit(pos);

    return ret;

}

inline void addedge(int u,int v,int flag)

{

    if( !flag ){

        edge[++nume].u = u,edge[nume].v = v,edge[nume].nxt = g[u],g[u] = nume;

        edge[++nume].u = v,edge[nume].v = u,edge[nume].nxt = g[v],g[v] = nume;

    }

    else{

        edge_v[++Nume].u = u,edge_v[Nume].v = v,edge_v[Nume].nxt = g_v[u],g_v[u] = Nume;

        edge_v[++Nume].u = v,edge_v[Nume].v = u,edge_v[Nume].nxt = g_v[v],g_v[v] = Nume;

    }

}

void init()

{

    memset(s,0,sizeof(s));

    memset(g,0,sizeof(g));

    memset(mark,0,sizeof(mark));

    nume = 1;

    for(int i = 1;i <= m;i++){

        int x,y;

        scanf("%d%d",&x,&y);

        addedge(x,y,0);

    }

}

void tarjan_dfs(int cur)

{

    low[cur] = dfn[cur] = ++cnt;

    st.push(cur);

    for(int i = g[cur];i;i = edge[i].nxt){

        if( mark[i] || mark[i^1] )

            continue;

        mark[i] = 1;

        int v = edge[i].v;

        if( !dfn[v] ){

            tarjan_dfs(v);

            low[cur] = min(low[cur],low[v]);

        }

        else

            low[cur] = min(low[cur],dfn[v]);

    }

    if( low[cur] == dfn[cur] ){

        ++bcc;

        while( 1 ){

            int temp = st.top();

            st.pop();

            cor[temp] = bcc;

            if( temp == cur )

                break;

        }

    }

}

void tarjan()

{

    while( !st.empty() )

        st.pop();

    cnt = bcc = 0;

    memset(low,0,sizeof(low));

    memset(dfn,0,sizeof(dfn));

    memset(cor,0,sizeof(cor));

    for(int i = 1;i <= n;i++)

        if( !dfn[i] )

            tarjan_dfs(i);

}

void tree_dfs(int cur,int fa)

{

    in_idx[cur] = ++cnt;

    mark[cur] = 1;

    for(int i = g_v[cur];i;i = edge_v[i].nxt){

        int v = edge_v[i].v;

        if( v != fa && !mark[v] )

            tree_dfs(v,cur);

    }

    out_idx[cur] = ++cnt;

}

void build_tree()

{

    memset(g_v,0,sizeof(g_v));

    Nume = 0;

    for(int i = 1;i <= nume;i++){

        int a = edge[i].u,b = edge[i].v;

        if( cor[a] != cor[b] )

            addedge(cor[a],cor[b],1);

    }

    memset(mark,0,sizeof(mark));

    cnt = 0;

    tree_dfs(cor[1],0);

}

const int main_stack = 16;

char my_stack[128 << 20];

int main()

{

    //freopen("in.txt","r",stdin);

    //freopen("out.txt","w",stdout);

    __asm__("movl %%esp, (%%eax);\n"::"a"(my_stack):"memory");

    __asm__("movl %%eax, %%esp;\n"::"a"(my_stack + sizeof(my_stack) - main_stack):"%esp");

    int q;

    char type[10];

    int a,b;

    while( scanf("%d%d%d",&n,&m,&q),n||m||q ){

        init();

        tarjan();

        build_tree();

        for(int i = 1;i <= q;i++){

            scanf("%s",type);

            if( type[0] == '+' ){

                scanf("%d%d",&a,&b);

                take_plus(in_idx[cor[a]],b);

                take_plus(out_idx[cor[a]]+1,-b);

            }

            else{

                scanf("%d",&a);

                int ans = take_sum(in_idx[cor[a]]);

                printf("%d\n",ans);

            }

        }

    }

    __asm__("movl (%%eax), %%esp;\n"::"a"(my_stack):"%esp");

    return 0;

}
View Code

 

你可能感兴趣的:(out)