zoukankan      html  css  js  c++  java
  • [IOI2018] werewolf 狼人

    题意:
    有一张无向图,一个人他需要从s走到t。
    他有两种形态,第一种形态可以走点编号为 ([ l_i,n ]) ,第二种形态可以走点编号为 ([ 1,r_i ]),可以点编号为 ([ l_i,n ])切换形态(恰好一次),在起点时为第一种形态。求他是否能从s走到t。
    多组询问。

    题解:
    首先我们可以维护与起点联通的点集合(形态一),同时也可以维护维护与终点联通的点集合(形态二),显然可以用Kruskal重构树维护。
    用主席树维护两棵重构树其中子树是否有并集(二位数点)。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=400010;
    int n,m,q,fa[N],w[N];
    vector <int> e[N];
    int tot=0,rt[N],lf[N*25],rf[N*25],sum[N*25];
    
    inline int read() {
    	register int tmp=0;register char c=getchar(); while(c<'0'||c>'9')	c=getchar();
    	while(c>='0'&&c<='9')	tmp=(tmp<<1)+(tmp<<3)+(c^48),c=getchar();return tmp;
    }
    //inline int Max(int x,int y) { return x>y?	x:y; }
    //inline int Min(int x,int y) { return x<y?	x:y; }
    int Find(int x) { return x==fa[x]?	x:fa[x]=Find(fa[x]); }
    struct Kruskal {
    	int type;
    	int cnt,hed[N],to[N],nxt[N];
    	int tot,w[N],idx,dfn[N],bg[N],ed[N];
    	int st[N][20];
    	inline void add(int x,int y) { to[++cnt]=y,nxt[cnt]=hed[x],hed[x]=cnt; }
    	void dfs(int u) {
    		dfn[bg[u]=++idx]=u; for(int i=1;i<20;i++)	st[u][i]=st[st[u][i-1]][i-1];
    		for(int i=hed[u];i;i=nxt[i])	dfs(to[i]);
    		ed[u]=idx;
    	}
    	void build() {
    		tot=n; for(int i=1;i<=n;++i)	fa[i]=i;
    		if(type) {
    			for(int i=n;i;--i)
    				for(int j=0;j<e[i].size();++j)
    					if(i<e[i][j]) {
    						int v=Find(e[i][j]); if(i==v)	continue;
    						add(i,v);fa[v]=st[v][0]=i;
    					}
    			dfs(1);
    		}
    		else {
    			for(int i=1;i<=n;++i)
    				for(int j=0;j<e[i].size();++j)
    					if(i>e[i][j]) {
    						int v=Find(e[i][j]); if(i==v)	continue;
    						add(i,v);fa[v]=st[v][0]=i;
    					}
    			dfs(n);
    		}
    	}
    	inline int find(int u,int x) {
    		for(int i=19;i>=0;i--)
    			if(st[u][i]&&((type&&x<=st[u][i])||(!type&&x>=st[u][i])))
    				u=st[u][i];
    		return u;
    	}
    };Kruskal mn,mx;// mn:people   mx:wolf
    
    void update(int &u,int v,int l,int r,int x) {
    	sum[u=++tot]=sum[v]+1,lf[u]=lf[v],rf[u]=rf[v]; if(l>=r)	return ;
    	int mid=(l+r)>>1; x<=mid?	update(lf[u],lf[v],l,mid,x):update(rf[u],rf[v],mid+1,r,x);
    }
    int ask(int u,int v,int l,int r,int L,int R) {
    	if(l==L&&r==R)	return sum[v]-sum[u];
    	int mid=(l+r)>>1;
    	if(R<=mid)	return ask(lf[u],lf[v],l,mid,L,R);
    	if(L>mid)	return ask(rf[u],rf[v],mid+1,r,L,R);
    	return ask(lf[u],lf[v],l,mid,L,mid)+ask(rf[u],rf[v],mid+1,r,mid+1,R);
    }
    int main() {
    	n=read(),m=read(),q=read();
    	for(int i=1,x,y;i<=m;++i)	x=read()+1,y=read()+1,e[x].push_back(y),e[y].push_back(x);
    	mn.type=1,mn.build(),mx.build();
    	for(int i=1;i<=n;++i)	w[mn.bg[i]]=mx.bg[i];
    	for(int i=1;i<=n;++i)	update(rt[i],rt[i-1],1,n,w[i]);
    	for(;q;--q) {
    		int s=read()+1,t=read()+1,l=read()+1,r=read()+1;
    		s=mn.find(s,l),t=mx.find(t,r);
    		if(ask(rt[mn.bg[s]-1],rt[mn.ed[s]],1,n,mx.bg[t],mx.ed[t]))	printf("1
    ");
    		else	printf("0
    ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    [060428]事件中的过去时和进行时,没想到是这种区别。
    4月11日,string这差距怎么就这么大呢
    暴一个vs2005的bug
    membership,想说爱你不容易
    4月5日,遇到一个GridView很头疼的问题
    ActiveX控件的打包发布[无证书发布]
    3月14号,oracle的说道多多
    [转载]在SQL Server数据库之间进行数据导入导出,OPENDATASOURCE Virus
    U盘加载,卸载,拔出,插入,WM_DEVICECHANGE,WndProc,DBT_DEVICEARRIVAL,DBT_DEVICEREMOVECOMPLETE Virus
    C#,String.Format,数字格式化输出 ,format Virus
  • 原文地址:https://www.cnblogs.com/daniel14311531/p/10164144.html
Copyright © 2011-2022 走看看