Regionals 2013 :: North America - Southeast USA
It Takes a Village
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.
题目大意:给定一张无向图带环图,不包含自边和重边。定义,
<1>如果P、Q两点间存在两条完全不重合路径;
<2>如果P到capital的路径经过Q,则P受Q的影响;
<3>P和Z互相影响,Z和Q互相影响,则P和Q互相影响。
Capital 恒为点1.
多组输入,包括n,m,q。(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; }