poj3694 Network Tarjan(树链剖分)

显然我们Tarjan桥边然后爆搞LCA。。。等等!这不是O(nq)的吗?嗯。。。。。799ms= =

每次缩点复杂度。。。不会证啊= =

我们还是考虑树剖吧,先Tarjan,然后缩点,这成为了一个树,乱搞LCA,然后我们维护重链的答案,维护清空标记,显然这就是一个裸的树剖。

这样复杂度就是O(qlognlogn)的了,这样才对嘛

然而已经成为了一个退役狗还是不在熄灯之前折腾自己了,有空再补代码。前面检查Tarjan的时候过掉了代码就贴一贴把

/* ***********************************************
Author        :BPM136
Created Time  :2016-5-3 20:36:54
File Name     :A.cpp
************************************************ */

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<utility>
#include<functional>
#include<numeric>
#include<memory>
#include<iterator>
#define LL long long
#define DB double
#define LB long double
#define UL unsigned long
#define ULL unsigned long long
#define pb push_back
#define popb pop_back
#define get(a,i) a&(1<<(i-1))
#define PAU putchar(32)
#define ENT putchar(10)
#define clr(a,b) memset(a,b,sizeof(a))
#define fo(_i,_a,_b) for(int _i=_a;_i<=_b;_i++)
#define fd(_i,_a,_b) for(int _i=_a;_i>=_b;_i--)
#define efo(_i,_a) for(int _i=last[_a];_i!=0;_i=e[_i].next)
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
#define mkd(x) freopen(#x".in","w",stdout);
#define setlargestack(x) int size=x<<20;char *p=(char*)malloc(size)+size;__asm__("movl %0, %%esp\n" :: "r"(p));
#define end system("pause")
using namespace std;
LL read()
{
         LL f=1,d=0;char s=getchar();
         while (s<48||s>57){if (s==45) f=-1;s=getchar();}
         while (s>=48&&s<=57){d=d*10+s-48;s=getchar();}
         return f*d;
}
LL readln()
{
       LL f=1,d=0;char s=getchar();
       while (s<48||s>57){if (s==45) f=-1;s=getchar();}
       while (s>=48&&s<=57){d=d*10+s-48;s=getchar();}
       while (s!=10) s=getchar();
       return f*d;
}
inline void write(LL x)
{
    if(x==0){putchar(48);return;}if(x<0)putchar(45),x=-x;
    int len=0,buf[20];while(x)buf[len++]=x%10,x/=10;
    for(int i=len-1;i>=0;i--)putchar(buf[i]+48);return;
}
inline void writeln(LL x){write(x);ENT;}

const int N = 100005;
const int M = 200005;

struct edge {
	int y,next;
}e[M*2];
int last[N],ne;
int dfn[N],Dfn[N],low[N],mark[N];
int n,m;
int fa[N];
int index,ans;

void add(int x,int y) {
	e[++ne].y=y;e[ne].next=last[x];last[x]=ne;
}
void add2(int x,int y) {
	add(x,y); add(y,x);
}

void init() {
	memset(last,0,sizeof(last)); ne=1;
	memset(Dfn,0,sizeof(Dfn));
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(mark,0,sizeof(mark));
	memset(fa,0,sizeof(fa)); index=0; ans=0;
	fo(i,1,m) {
		int x=read(),y=read();
		add2(x,y);
	}
}

void Tarjan(int x) {
	dfn[x]=low[x]=++index;
	Dfn[x]=Dfn[fa[x]]+1;
	efo(i,x) {
		int y=e[i].y;
		if(!dfn[y]) {
			fa[y]=x;
			Tarjan(y);
			low[x]=min(low[x],low[y]);
			if(low[y]>dfn[x]) {
				ans++;
				mark[y]=1;
			}
		} else {
			if(y!=fa[x]) low[x]=min(low[x],dfn[y]);
		}
	}
}

void LCA(int x,int y) {
	while(Dfn[x]>Dfn[y]) {
		if(mark[x]) ans--,mark[x]--;
		x=fa[x];
	}
	while(Dfn[x]<Dfn[y]) {
		if(mark[y]) ans--,mark[y]--;
		y=fa[y];
	}
	while(x!=y) {
		if(mark[x]) ans--,mark[x]--;
		if(mark[y]) ans--,mark[y]--;
		x=fa[x], y=fa[y];
	}
}

void work() {
	Tarjan(1);
	int T=read();
	while(T--) {
		int x=read(),y=read();
		LCA(x,y);
		writeln(ans);
	}
	ENT;
}


int main() {
	file(A);
	int T = 0;
	while(scanf("%d%d",&n,&m)!=EOF) {
		if(n==0&&m==0) return 0;
		printf("Case %d:\n",++T);
		init();
		work();
	}
	return 0;
}


你可能感兴趣的:(Tarjan,树链剖分)