zoukankan      html  css  js  c++  java
  • [WC2018] 即时战略

    题目

    终于会写交互了

    粗略观察一下,发现这道题树的部分查询次数要求是(O(nlog n))级别,链部分要求是(O(n))级别而且要求这个常数比较小

    先来考虑链怎么搞,我们可以随机一个序列,之后按照顺序explore这些点,如果一个点已经被探明了,我们就跳过它;我们维护当前已经扩展出来的这条链的左右端点,每次遇到一个未探明点时,就用这左右两个端点分别explore一下,看看这个点在哪个端点的下面,之后一直搞下去,直到这个点被探明为止,之后再将这个点设为新的端点。

    不难发现这样每个点最多会被explore两次,这询问次数好像有点超的样子;但是我们随机了序列,这相当于对链的两边做随机分治,于是询问次数是期望(n+log n)的。

    再来考虑树的情况,一个直观的想法是分治,设当前的根为(x),我们把(x)子树内部的点跟(x)explore一遍,之后按照得到的结果把他们分到不同的子树中去;这样的询问次数是(sum_{i=1}^ndep_i),又能过完全二叉树的subtask了。

    这个询问次数太垃圾了,我们需要做的是将每个点的询问次数优化到(log n)

    假如我们现在有一棵点分树,如果我们要探明一个点(x),我们就explore一下当前分治重心与(x);我们把得到的结果一路暴跳,这样就能知道下一层的分治重心是谁,之后继续到下一层的分治重心去询问,直到(x)被探明,之后再把(x)加入点分树。

    这样探明(x)的询问次数是点分树的树高次,时间复杂度是点分树树高的平方次,于是只要我们能保证点分树(log)的树高,就能解决这个问题了。于是是我们只需要一个替罪羊重构就好了。

    这样询问次数是(O(nlog n))的,时间复杂度是(O(nlog^2 n))

    代码

    #include<bits/stdc++.h>
    #include "rts.h"
    #define re register
    #define max(a,b) ((a)>(b)?(a):(b))
    const int maxn=3e5+5;
    int c[maxn],p[maxn];
    std::vector<int> d[maxn];
    void dfs(int x,int fa,int n) {
    	for(re int i=2;i<=n;i++) {
    		if(c[i]) continue;
    		int v=explore(x,i);
    		if(c[v]) continue;
    		c[v]=1;dfs(v,x,n);
    	}
    }
    void divide(int x) {
    	int rt[2];rt[0]=rt[1]=0;
    	for(re int i=0;i<d[x].size();++i) {
    		if(x==d[x][i]) continue;
    		int t=explore(x,d[x][i]);
    		d[t].push_back(d[x][i]);
    		if(rt[0]==t||rt[1]==t) continue;
    		if(!rt[0]) rt[0]=t;
    		else if(!rt[1]) rt[1]=t;
    	}
    	if(rt[0]) divide(rt[0]);
    	if(rt[1]) divide(rt[1]);
    }
    const double alpha=0.75;
    struct E{int v,nxt;}e[maxn<<1];
    int head[maxn],Mnow,sum[maxn],vis[maxn],nrt,S,rt,mx[maxn],fa[maxn],num,tim,del[maxn];
    inline void add(int x,int y) {
    	e[++num].v=y;e[num].nxt=head[x];head[x]=num;
    }
    void getrt(int x,int Fa) {
    	sum[x]=1;mx[x]=0;
    	for(re int i=head[x];i;i=e[i].nxt) {
    		if(vis[e[i].v]==tim||e[i].v==Fa)continue;
    		getrt(e[i].v,x);sum[x]+=sum[e[i].v];
    		mx[x]=max(sum[e[i].v],mx[x]);
    	}
    	mx[x]=max(mx[x],S-sum[x]);
    	if(mx[x]<Mnow) Mnow=mx[x],nrt=x;
    }
    void clr(int x,int Fa) {
    	del[x]=0;
    	for(re int i=head[x];i;i=e[i].nxt) {
    		if(e[i].v==Fa||vis[e[i].v]==tim) continue;
    		clr(e[i].v,x);
    	}
    }
    void Dfs(int x) {
    	vis[x]=tim;
    	for(re int i=head[x];i;i=e[i].nxt) {
    		if(vis[e[i].v]==tim) continue;
    		Mnow=maxn,S=sum[e[i].v];getrt(e[i].v,0);
    		fa[nrt]=x;sum[nrt]=sum[e[i].v];Dfs(nrt);
    	}
    }
    inline void rebuild(int x) {
    	++tim;for(re int i=fa[x];i;i=fa[i]) vis[i]=tim;
    	clr(x,0);Mnow=maxn,S=sum[x],getrt(x,0);
    	if(rt==x) rt=nrt;
    	fa[nrt]=fa[x];sum[nrt]=sum[x];Dfs(nrt);
    }
    inline void pushup(int x) {
    	if(!fa[x]) {
    		if(del[x]) rebuild(x);
    		return;
    	}
    	++sum[fa[x]];if(sum[fa[x]]*alpha<sum[x]) del[fa[x]]=1;
    	pushup(fa[x]);if(del[x]) rebuild(x);
    }
    inline void ins(int x) {
    	int u=rt;
    	while(!c[x]) {
    		int v=explore(u,x);
    		if(c[v]) {
    			while(fa[v]!=u) v=fa[v];
    			u=v;continue;
    		}
    		add(u,v),add(v,u);fa[v]=u;
    		sum[v]=1;pushup(v);
    		u=v;c[v]=1;
    	}
    }
    void play(int n, int T, int dataType) {
    	if(n<=100&&dataType==1) {
    		dfs(1,0,n);return;
    	}
    	if(dataType==3) {
    		for(re int i=1;i<n;++i)p[i]=i+1;
    		srand(time(0));
    		std::random_shuffle(p+1,p+n);
    		int rt[2];rt[0]=1,rt[1]=1;
    		int t=p[2],u;
    		while(rt[1]!=t) {
    			u=explore(rt[1],t);
    			c[u]=1;rt[1]=u;
    		}
    		for(re int i=3;i<n;i++) {
    			int x=p[i];if(c[x]) continue;
    			u=explore(rt[0],x);
    			if(c[u]) std::swap(rt[0],rt[1]),u=explore(rt[0],x);
    			c[u]=1,rt[0]=u;
    			while(rt[0]!=x) {
    				u=explore(rt[0],x);
    				c[u]=1,rt[0]=u;
    			}
    		}
    	}
    	if(dataType==2) {
    		for(re int i=2;i<=n;i++) d[1].push_back(i);
    		divide(1);
    		return;
    	}
    	rt=1;for(re int i=1;i<n;i++)p[i]=i+1;
    	srand(time(0));std::random_shuffle(p+1,p+n);
    	for(re int i=1;i<n;i++) if(!c[p[i]]) ins(p[i]);
    }
    
  • 相关阅读:
    android 底部菜单栏实现(转)
    android 用webView作为编辑器 各种问题
    android 自定图库(转)
    js document.queryCommandState() 各个参数
    自定义简单的按钮点击动画效果
    android 类似QQ底部输入框弹出键盘和面板冲突 布局闪动处理方案(转)
    android 自定义控件View在Activity中使用findByViewId得到结果为null
    Tinker 热修复框架 简单上手教程
    网页天气模块,包括当天天气和未来四天预报
    关于闭包(closure)的一些概念
  • 原文地址:https://www.cnblogs.com/asuldb/p/12182816.html
Copyright © 2011-2022 走看看