• UOJ#349. 【WC2018】即时战略


    UOJ#349. 【WC2018】即时战略

    http://uoj.ac/problem/349

    分析:

    • 对于链的数据,我们瞎随就行,肯定能过去。
    • 否则我们希望用一种不超过(log)次询问来找到某个点。
    • 首先还是要随机这个询问序列。
    • 维护点分树,每次询问后一直跳点分树的父亲,用来求出进入了哪棵点分树中子树。
    • 直到这个点未被标记,则插入这个点。
    • 这里我使用替罪羊式重构的方法维护这棵点分树。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #include <cstdlib>
    #include "rts.h"
    using namespace std;
    #define N 300050
    #define pb push_back
    #define ep explore
    #define AL 0.75
    int n,Q[N],S[N],vis[N],cnt,head[N],to[N<<1],nxt[N<<1];
    int used[N],tot;
    vector<int>v[N];
    int tt[N],rt,fa[N],siz[N],fk[N],root,g[N];
    void chain() {
    	int p=1,q=1,i;
    	for(i=1;i<=n;i++) tt[i]=i;
    	random_shuffle(tt+2,tt+n+1);
    	i=1;
    	vis[1]=1;
    	while(1) {
    		for(;i<=n&&vis[tt[i]];i++) ;
    		if(i>n) break;
    		int r=ep(p,tt[i]);
    		if(vis[r]) {
    			r=ep(q,tt[i]);
    			q=r; vis[q]=1;
    			while(q!=tt[i]) {
    				int t=ep(q,tt[i]);
    				vis[t]=1; q=t;
    			}
    		}else {
    			p=r; vis[p]=1;
    			while(p!=tt[i]) {
    				int t=ep(p,tt[i]);
    				vis[t]=1; p=t;
    			}
    		}
    		swap(p,q);
    	}
    }
    inline void add(int u,int v) {
    	to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
    }
    void gr(int x,int y) {
    	int i; g[x]=1; fk[x]=0;
    	for(i=head[x];i;i=nxt[i]) if(to[i]!=y&&!used[to[i]]) {
    		gr(to[i],x); g[x]+=g[to[i]];
    		fk[x]=max(fk[x],g[to[i]]);
    	}
    	fk[x]=max(fk[x],tot-g[x]);
    	if(fk[x]<fk[root]) root=x;
    }
    void gd(int x,int y,int rt) {
    	int i;
    	siz[rt]++; v[rt].push_back(x);
    	for(i=head[x];i;i=nxt[i]) if(to[i]!=y&&!used[to[i]]) {
    		gd(to[i],x,rt);
    	}
    }
    void solve(int x) {
    	used[x]=1;
    	int i,al=tot;
    	v[x].clear();
    	siz[x]=0; gd(x,0,x);
    	for(i=head[x];i;i=nxt[i]) if(!used[to[i]]) {
    		tot=g[to[i]]; if(tot>g[x]) tot=al-g[x];
    		root=0; gr(to[i],x); fa[root]=x; solve(root);
    	}
    }
    void insert(int x) {
    	int t,koishi=0,i;
    	for(t=x;t;t=fa[t]) {
    		siz[t]++; v[t].push_back(x);
    		if(fa[t]&&siz[t]>siz[fa[t]]*AL) koishi=fa[t];
    	}
    	if(koishi) {
    		int p=koishi,tmp=fa[p];
    		int lim=v[p].size();
    		for(i=0;i<lim;i++) used[v[p][i]]=0;
    		tot=lim;
    		root=0;
    		gr(p,0);
    		fa[root]=tmp;
    		if(!tmp) rt=root;
    		solve(root);
    	}
    }
    void play(int _n,int _T,int dataType) {
    	n=_n;
    	if(dataType==3) {
    		chain(); return ;
    	}
    	int i;
    	for(i=1;i<=n;i++) tt[i]=i;
    	srand(1919810);
    	random_shuffle(tt+2,tt+n+1);
    	vis[1]=1; rt=1; siz[1]=1; v[1].push_back(1); fk[0]=1<<30;
    	for(i=2;i<=n;i++) {
    		int x=tt[i],p=rt;
    		while(!vis[x]) {
    			int q=ep(p,x);
    			if(vis[q]) {
    				for(;fa[q]!=p;q=fa[q]);
    				p=q;
    			}else {
    				add(p,q); add(q,p);
    				fa[q]=p;
    				vis[q]=1;
    				insert(q);
    				p=q;
    			}
    		}
    	}
    	return ;
    }
    
    
  • 相关阅读:
    SQL语言的组成
    存储过程中使用事务
    sql语法:inner join on, left join on, right join on详细使用方法
    Sql Server服务 远程过程调用失败
    UML学习之初步总结
    UML学习之用例图
    使用redis
    msserver的update or insert语句
    c#操作注册表的意外
    托管代码编写mssql存储过程
  • 原文地址:https://www.cnblogs.com/suika/p/10205999.html
Copyright © 2020-2023  润新知