首页 > 其他分享 >【题解】[IOI2018] werewolf 狼人

【题解】[IOI2018] werewolf 狼人

时间:2023-01-28 20:22:05浏览次数:50  
标签:IOI2018 return val int 题解 狼人 fa edge now

题目分析

这个题本身很简单,可能就是因为是 IOI 题所以看上去就难了些吧。

其实题目就是让我们先走一段全部大于等于 \(l\) 的点然后再走一段全部小于等于 \(r\) 的点,那么能成功走过显然就是从 \(s\) 开始全部走大于等于 \(l\) 能到的点与从 \(e\) 开始走全部大于等于 \(r\) 能到的点有交。
那么现在就是怎么去找那些点的问题了,我们可以想到在 \(Kruskal\) 重构树中从一个点走到另一个点的子树内所满足的性质有点类似上面这个,只不过需要考虑一下边权怎么弄。其实很好搞,对于从 \(s\) 开始的将边权设为连接的点的编号的 \(\min\) 从 \(e\) 开始的则设为 \(\max\) 分别建 \(Kruskal\) 重构树就可以将上述条件转化为两棵子树判断是否有交了。

看上去还是不好搞,我们也知道对于同一棵子树内的节点其 \(dfs\) 序,所以我们其实就是可以转化为给定两个排列 \(a,b\),分别划定一段区间,判断区间是否有交。
那么我们就可以使用类似映射,即求出 \(b\) 中的元素在 \(a\) 位置,然后就是判断 \(b\) 的这一段对应的权值中 \(a\) 的那一段区间和是否为 \(0\)。
直接主席树去维护就好了。

感觉这个题的难点最在于一开始的条件转化,之后就是套路分析了。

代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
struct edge{
	int nxt,to,val,from;
	edge(){}
	edge(int _nxt,int _to){
		nxt = _nxt,to = _to;
	}
};
int n,m,q,tot,sum[60*N],lson[60*N],rson[60*N],pos[N],rt[N];
bool cmp1(edge a,edge b){return a.val > b.val;}
bool cmp2(edge a,edge b){return a.val < b.val;}
struct Kruskal{
	edge e[2*N],a[2*N];
	int tmp,cnt,head[N],in[N],out[N],dfn[N],val[N],fa[N][22],res,f[N],id[N];
	bool mark = false;
	void add_edge(int from,int to){
		e[++cnt] = edge(head[from],to);
		head[from] = cnt;
	}
	int find(int x){
		if(f[x] == x)	return x;
		return f[x] = find(f[x]);
	}
	void dfs(int now,int fath){
		fa[now][0] = fath;in[now] = tmp + 1;
		if(now <= n)	dfn[now] = ++tmp,id[tmp] = now;
		for(int i = head[now]; i;i = e[i].nxt){
			int to = e[i].to;
			if(to == fath)	continue;
			dfs(to,now);
		}
		out[now] = tmp;
	}
	void pre_lca(){
		for(int i=1; i<=20; i++){
			for(int j=1; j<=2*n-1; j++){
				fa[j][i] = fa[fa[j][i-1]][i-1];
			}
		}
	}
	void init(){
		for(int i=1; i<=2*n-1; i++)	f[i] = i;
		if(mark)	sort(a+1,a+m+1,cmp1);
		else	sort(a+1,a+m+1,cmp2);
		int res = n;
		for(int i=1; i<=m; i++){
			int x = find(a[i].from),y = find(a[i].to);
			if(x != y){
				f[x] = f[y] = ++res;
				val[res] = mark ? min(a[i].from,a[i].to) : max(a[i].from,a[i].to);
				add_edge(x,res);add_edge(res,x);
				add_edge(y,res);add_edge(res,y);
			}
		}
		dfs(res,0);
		pre_lca();
	}
	int get1(int now,int x){
		for(int i = 20; i>=0; i--){
			if(fa[now][i] && val[fa[now][i]] >= x){
				now = fa[now][i];
			}
		}
		return now;
	}
	int get2(int now,int x){
		for(int i=20; i>=0; i--){
			if(fa[now][i] && val[fa[now][i]] <= x){
				now = fa[now][i];
			}
		}
		return now;
	}
}A,B;
int insert(int lst,int now_l,int now_r,int pos){
	int now = ++tot;
	if(now_l == now_r){
		sum[now] = sum[lst] + 1;
		return now;
	}
	int mid = (now_l + now_r)>>1;
	if(pos <= mid)	lson[now] = insert(lson[lst],now_l,mid,pos),rson[now] = rson[lst];
	else	rson[now] = insert(rson[lst],mid+1,now_r,pos),lson[now] = lson[lst];
	sum[now] = sum[lson[now]] + sum[rson[now]];
	return now;
}
int query(int l,int r,int now_l,int now_r,int ql,int qr){
	if(ql <= now_l && qr >= now_r)	return sum[r] - sum[l];
	int mid = (now_l + now_r)>>1,ans = 0;
	if(ql <= mid)	ans += query(lson[l],lson[r],now_l,mid,ql,qr);
	if(qr > mid)	ans += query(rson[l],rson[r],mid+1,now_r,ql,qr);
	return ans;
}
int main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	A.mark = true;
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1; i<=m; i++){
		int from,to;scanf("%d%d",&from,&to);
		from++;to++;
		A.a[i].from = from;A.a[i].to = to;A.a[i].val = min(from,to);
		B.a[i].from = from;B.a[i].to = to;B.a[i].val = max(from,to);
	}
	A.init();B.init();
	for(int i=1; i<=n; i++)	pos[i] = A.dfn[i];
	for(int i=1; i<=n; i++)	rt[i] = insert(rt[i-1],1,n,pos[B.id[i]]);
//	printf("\n");
	for(int i=1; i<=q; i++){
		int s,t,l,r;scanf("%d%d%d%d",&s,&t,&l,&r);
		s++;t++;l++;r++;
		s = A.get1(s,l);t = B.get2(t,r);
//		printf("%d %d\n",s,t);
		printf("%d\n",query(rt[B.in[t]-1],rt[B.out[t]],1,n,A.in[s],A.out[s]) >= 1);
//		printf("%d %d %d %d\n",B.in[t]-1,B.out[t],A.in[s],A.out[s]);
	}
	return 0;
}

标签:IOI2018,return,val,int,题解,狼人,fa,edge,now
From: https://www.cnblogs.com/linyihdfj/p/17071060.html

相关文章

  • xhost: unable to open display ""问题解决
    一、需求xhost可是增强vnc的图形界面显示二、问题解决设置一下dispaly  通过执行exportDISPLAY=x.x.x.x:1,x.x.x.x指的是虚拟机ip地址,DISPLAY用来设置将图形显示......
  • 视频美颜sdk疑难问题解答
    目前,美颜sdk已经成了大多数直播、视频平台的刚需,因为这是用户需求,同样也是市场的风向。随着需求量的暴增,视频美颜sdk一些技术向的提问也多了起来,今天小编就为大家讲解一下视......
  • # CF#847 (Div. 3)ABCDE题解
    CodeforcesRound#847(DFiv.3)APolycarpandtheDayofPiProblem-A-Codeforces题目描述OnMarch14,thedayofthenumber$\pi$iscelebratedallov......
  • 【题解】洛谷-P5643 [PKUWC2018]随机游走
    用到了概率期望的很多技巧。首先要求的是走遍集合中所有节点步数的期望,也就是步数最大值的期望,根据\(\text{min-max}\)容斥,有:\[E\left(\max_{i\inS}x_i\right)=\sum_......
  • 题解 CF1670F【Jee, You See?】
    problem给出常数\(n,z\),令\(F(m)\)表示所有满足以下条件的数列\(\{a_i\}\)的数量:\(\{a_i\}\)有\(n\)项,都是非负整数。它们的和不大于\(m\)。它们的异或和恰......
  • 【ElementPlus】el-menu侧边垂直菜单折叠后图标会消失的问题解决
    首先上代码<template><templatev-for="subIteminmenuList":key="subItem.path"><!--有子菜单--><el-sub-menuv-if="subItem.children&&s......
  • CF908G 题解
    题意传送门给\(x\le10^{700}\),问\(1\)到\(x\)中每个数在各数位排序后得到的数的和。答案模\(10^9+7\)。题解学到一种新鲜的转化方式,来记一下。将\(x\)的位数......
  • Codeforces 708 A-E1题解
    A.Meximization这道题问给一些数,如何让前缀的mex之和最大,那么首先,我们要抬mex的话肯定是要把前面都铺垫完的,所以在i位置确定的时候,i+1自然是越大越好,可以证明i+1的位......
  • Atcoder ABC244E - King Bombee 题解
    原题:AtcoderABC244E-KingBombee题意给你一张图,从\(S\)到\(T\),经过\(k\)条边,经过\(X\)号点偶数次的方案数。做法设\(f_{i,j,k}\)表示经过\(i\)条边,......
  • 洛谷 P1208混合牛奶 题解
    一道贪心算法不是很明显的题目,其实一般的递推也可以做。 大体思路:肯定优先购买单价最低的奶农的牛奶,那么就需要先根据牛奶单价进行排序,这里用结构体会更好一点。之后在......