[SDOI2017]天才黑客(虚树优化建边)

题目
rep实在是太优越了。
以边为点,菊花难受。
菊花周围边在字典树上建两颗虚树,
一颗入虚树,一颗出虚树,入虚树的一个点向其的兄弟在出虚树的对应点上连边,
此时用前缀和连边即可。
点边数 O ( n ) O(n) O(n),时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)
但是好像点的常数有点大,直逼 5 e 5 5e5 5e5
A C   C o d e \mathrm{AC\ Code} AC Code

#include
#define maxn 100005
#define maxm 100005
#define maxp 1500005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define Clear(a,b) memset(a,b,sizeof a)
#define pb push_back
#define Ct const
#define LL long long
using namespace std;

char cb[1<<16],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<16,stdin),cs==ct)?0:*cs++)
void read(int &res){char ch;bool f=0;
	for(;!isdigit(ch=getc());) if(ch=='-') f=1;
	for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
	(f) && (res = -res);
}

int n,m,K,N;
int info[maxn],Prev[maxm],to[maxm],cst[maxm],d[maxm],cnt_e;
#define lim 16
int MN[lim][maxn],cnt_ar;
void Node(int u,int v,int c){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cst[cnt_e]=c; }
int fir[maxp],nxt[maxp],tar[maxp],cts[maxp],cnte;
void add(int u,int v,int w=0){ nxt[++cnte]=fir[u],fir[u]=cnte,tar[cnte]=v,cts[cnte]=w; }

int fa[maxn],dep[maxn],lg[maxn],st[maxn];
void dfs(int u,int ff){
	MN[0][st[u] = ++cnt_ar]=u,dep[u]=dep[fa[u]=ff]+1;
	if(u == 1) dep[u] = 0;
	for(int i=fir[u],v;i;i=nxt[i]) if((v=tar[i])^ff)
		dfs(v,u),MN[0][++cnt_ar]=u;
}
int LCA(int u,int v){ u=st[u],v=st[v]; 
	if(u>v) swap(u,v);int t = lg[v-u+1];
	return dep[MN[t][u]] < dep[MN[t][v-(1<<t)+1]] ? MN[t][u] : MN[t][v-(1<<t)+1];
}
bool cmp(Ct int &u,Ct int &v){ return st[u] < st[v]; }
LL dis[maxp],ans[maxn];
#define pii pair
#define mp make_pair
vector<int>in[maxn],ot[maxn];

int main(){
	int T;
	rep(i,2,maxn-1) lg[i]=lg[i>>1]+1;
	for(read(T);T--;){cnt_ar=0;
		read(n),read(m),read(K);N=m;
		rep(i,1,m){ int u,v,w;read(u),read(v),read(w),read(d[i]);Node(u,v,w);
		in[v].pb(i); ot[u].pb(i);}
		rep(i,1,K-1){ int u,v,w;read(u),read(v),read(w);add(u,v); }
		dfs(1,0);
		rep(i,1,K) fir[i] = 0;cnte=0;
		rep(j,1,lim-1) rep(i,1,cnt_ar-(1<<j)+1) MN[j][i]=dep[MN[j-1][i]] < dep[MN[j-1][i+(1<<j-1)]] ? MN[j-1][i] : MN[j-1][i+(1<<j-1)];
		static int ar[maxp]={},q[maxp]={},pts[maxp]={},nid[maxp][2]={},bl[maxp]={},zpt[maxp][2]={},R=0,cnt=0;
		rep(i,1,n){ar[0]=0;
			rep(j,0,in[i].size()-1) ar[++ar[0]]=d[in[i][j]];
			rep(j,0,ot[i].size()-1) ar[++ar[0]]=d[ot[i][j]];
			sort(ar+1,ar+1+ar[0],cmp);
			ar[0]=unique(ar+1,ar+1+ar[0])-ar-1;
 			rep(j,1,ar[0]){
 				if(R){
				 	int t=LCA(ar[j],q[R]),p=0;
 					for(;R&&dep[q[R]]>dep[t];p=q[R--]) p&&(add(nid[p][0],nid[q[R]][0]),add(nid[q[R]][1],nid[p][1]),0);
 					if(q[R]^t) q[++R]=pts[++cnt]=t,bl[nid[t][0]=++N]=t,bl[nid[t][1]=++N]=t;
 					if(p) add(nid[p][0],nid[q[R]][0]),add(nid[q[R]][1],nid[p][1]);
				}
				q[++R]=pts[++cnt]=ar[j],bl[nid[ar[j]][0]=++N]=ar[j],bl[nid[ar[j]][1]=++N]=ar[j];
			}
			for(int p=0;R;p=q[R--]) if(p) add(nid[p][0],nid[q[R]][0]),add(nid[q[R]][1],nid[p][1]);
			rep(j,1,cnt){
				int u = pts[j] , p = nid[u][1];
				static int sta[maxp]={},tp=0;
				tp=0;
				for(int k=fir[p],v;k;k=nxt[k]){v=tar[k];
					add(zpt[v][0] = ++N , v);
					int g = nid[bl[v]][0];
					if(tp){
						add(zpt[v][0],N-1),
						add(g,N-1,dep[u]);
					}
					sta[++tp] = v;
				}
				per(k,tp,1){
					int v = sta[k] , g = nid[bl[v]][0];
					add(zpt[v][1]=++N,v);
					if(k<tp){
						add(zpt[v][1],N-1),
						add(g,N-1,dep[u]);
					}
				}
			}
			rep(j,0,in[i].size()-1) add(in[i][j],nid[d[in[i][j]]][0]),add(in[i][j],nid[d[in[i][j]]][1],dep[d[in[i][j]]]);
			rep(j,0,ot[i].size()-1) add(nid[d[ot[i][j]]][1],ot[i][j],cst[ot[i][j]]),add(nid[d[ot[i][j]]][0],ot[i][j],cst[ot[i][j]]+dep[d[ot[i][j]]]);
			cnt = 0;
 		}
 		rep(i,1,N) dis[i] = 0x7f7f7f7f;
 		rep(i,2,n) ans[i] = 0x7f7f7f7f;
 		static priority_queue<pii,vector<pii >,greater<pii > >Q;
 		for(int i=info[1];i;i=Prev[i])
 			dis[i] = cst[i] , Q.push(mp(dis[i],i));
 		LL w;
		for(int u;!Q.empty();){
 			u = Q.top().second , w = Q.top().first , Q.pop();
 			if(w > dis[u]) continue;
 			for(int i=fir[u],v;i;i=nxt[i]){
			 	if(dis[v=tar[i]] > dis[u] + cts[i]){
	 				dis[v] = dis[u] + cts[i];
	 				Q.push(mp(dis[v] , v));
				}
			}
		}
		rep(i,1,m) ans[to[i]] = min(ans[to[i]] , dis[i]);
		rep(i,2,n) printf("%d%c",ans[i],'\n');
		rep(i,1,n) info[i] = 0 , in[i].clear(), ot[i].clear();cnt_e = 0;
		rep(i,1,N) fir[i] = 0;cnte=0;
	}
}

你可能感兴趣的:(虚树,优化建边)