20211118 NOIP 灌水模拟赛

前言

信心赛一点也不影响我挂70分

同志们!double是四舍五入保留小数位!!!

T1

题面把我唬住了,想了半天没想出来。看一眼数据范围,这不是傻逼题吗??

取整挂了70分,我吐了

思路:
枚举流量然后dijkstra计算费用。\(O(n^2 \log n)\)水过去

#include<bits/stdc++.h>
#define in read()
using namespace std;
typedef long long ll;
inline int read(){
	static char ch;
	int res=0,sign=1;
	while((ch=getchar())<'0'||ch>'9'){
		if(ch=='-') sign=-1;
	}
	res=ch-'0';
	while((ch=getchar())>='0'&&ch<='9'){
		res=res*10+ch-'0';
	}
	return res*sign;
}
int n,m;
const int N=1e4;
const int INF=0x3f3f3f3f;
int head[N],to[N*2],w[N*2],nxt[N*2],cost[N*2];
int cnt;
void add(int u,int v,int z,int val){
	nxt[++cnt]=head[u];
	head[u]=cnt;
	w[cnt]=z;
	to[cnt]=v;
	cost[cnt]=val;
}
int dis[N],vis[N];
int dijkstra(int mid){
	priority_queue<pair<int,int> >q;
	for(int i=1;i<=n;i++){
		dis[i]=INF;
		vis[i]=0;
	}
	dis[1]=0;
	q.push(make_pair(0,1));
	while(!q.empty()){
		int u=q.top().second;
		q.pop();
		if(vis[u]) continue;
		vis[u]=1;
		for(int i=head[u];i;i=nxt[i]){
			int v=to[i];
			if(dis[v]>dis[u]+w[i]&&cost[i]>=mid){
				dis[v]=dis[u]+w[i];
				q.push(make_pair(-dis[v],v));
			}
		}
	}
	return dis[n];
}
map<int,int> Q;
int main(){
	freopen("pump.in","r",stdin);
	freopen("pump.out","w",stdout);
	n=in,m=in;
	for(int i=1;i<=m;i++){
		int a,b,c,d;
		a=in,b=in,c=in,d=in;
		Q[d]++;
		add(a,b,c,d);
		add(b,a,c,d);
	}
	double ans=0.0;
	for(int i=1;i<=1000;i++){
		if(Q[i]==0) continue;
		double a=dijkstra(i);
		double b=i;
		if(!a) continue;
		ans=max(ans,(b/a));
	}
	ans*=1000000;
	ans=(int)ans;
	printf("%.0lf\n",ans);
	
	
	
	return 0;
}

T2

考前做过好无聊~~;
lca再加上树上前缀和即可

不放代码了

T3

T2的加强版;
思路有好几种,不过我比较喜欢树链剖分加上二分。\(O(n \log^2 n)\)

思路就是,vector记录每种颜色在欧拉序上出现的下标,每次二分查找vector\([id[top[a]],id[a]]\)之间有没有出现。

隔壁巨佬用树套树过了。\(O(n \log^3 n)\)

算法一:

#include<bits/stdc++.h>
#define in read()
#define int long long
using namespace std;
const int N=1e5+7;
inline int read(){
	static char ch;
	int res=0,sign=1;
	while((ch=getchar())<'0'||ch>'9'){
		if(ch=='-') sign=-1;
	}
	res=ch-'0';
	while((ch=getchar())>='0'&&ch<='9'){
		res=res*10+ch-'0';
	}
	return res*sign;
}
int a[N];
int head[N],nxt[N*2],to[N*2],e;
int top[N],fa[N],son[N],siz[N],id[N],atid[N],dep[N],cnt;
int ans[N],qwq=0;
vector<int>v[N];
int n,m;
void add(int u,int v){
	to[++e]=v;
	nxt[e]=head[u];
	head[u]=e;
}

void dfs1(int u,int father){
	siz[u]=1;
	fa[u]=father;
	son[u]=-1;
	for(int i=head[u];i;i=nxt[i]){
		int v=to[i];
		if(v==father) continue;
		dfs1(v,u);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]]||son[u]==-1){
			son[u]=v;
		}
	}
	return ;
}

void dfs2(int u,int topf){
	top[u]=topf;
	id[u]=++cnt;
	atid[cnt]=u;
	if(son[u]) dfs2(son[u],topf);
	for(int i=head[u];i;i=nxt[i]){
		int v=to[i];
		if(v==fa[u]||v==son[u]){
			continue;
		}
		dfs2(v,v);
	}
}


signed main(){
	n=in,m=in;
	for(int i=1;i<=n;i++){
		a[i]=in;
	}
	for(int i=1;i<n;i++){
		int a,b;
		a=in,b=in;
		add(a,b);
		add(b,a);
	}
	dfs1(1,1);
	dfs2(1,1);
	for(int i=1;i<=cnt;i++){
		v[a[atid[i]]].push_back(i);
	}
	while(m--){
		int a,b,c;
		a=in,b=in,c=in;
		int flag=0;
		while(top[a]!=top[b]){
			if(id[top[a]]<id[top[b]]) swap(a,b);
			vector<int>::iterator it=lower_bound(v[c].begin(),v[c].end(),id[top[a]]);
			if(it!=v[c].end()&&*it<=id[a]){
				flag=1;
				break;
			}
			a=fa[top[a]];
		}
		if(!flag){
			if(id[a]>id[b]) swap(a,b);
			vector<int>::iterator it=lower_bound(v[c].begin(),v[c].end(),id[a]);
			if(it!=v[c].end()&&*it<=id[b]){
				flag=1;
			}
		}
		ans[++qwq]=flag;
	}
	for(int i=1;i<=qwq;i++){
		cout<<ans[i];
	}
	return 0;
}

算法二:

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pb push_back
#define mp make_pair
#define ll long long
#define gc getchar
#define REP(i,x,y) for(int i=x;i<=y;i++)
#define rep(i,n) REP(i,1,n)
#define rep0(i,n) REP(i,0,n-1)
#define repp(i,n) for(int i=n;i>=1;i--)
#define repG(e) for(int e=hd[u];e;e=nt[e])
inline int read(){
	int x=0;char v=gc();
	while(!isdigit(v))v=gc();
	while(isdigit(v))x=(x<<1)+(x<<3)+(v^48),v=gc();
	return x;
}
cs int N=1e5+10;
int hd[N],nt[N<<1],to[N<<1],tot;
inline void add(int x,int y){
	nt[++tot]=hd[x];
	hd[x]=tot;
	to[tot]=y;
}
int n,q;
int a[N];
int fa[N],sz[N],top[N],son[N],id[N],rev[N],dep[N],cnt;
inline void dfs1(int u,int f){
	sz[u]=1;
	fa[u]=f;
	dep[u]=dep[f]+1;
	repG(e)if(to[e]^f){
		dfs1(to[e],u);
		if(sz[to[e]]>sz[son[u]])son[u]=to[e];
	}
	sz[f]+=sz[u];
}
inline void dfs2(int u){
	id[u]=++cnt;
	rev[cnt]=u;
	if(son[fa[u]]^u)top[u]=u;
	else top[u]=top[fa[u]];
	if(son[u])dfs2(son[u]);
	repG(e)if((to[e]^fa[u])&&(to[e]^son[u]))dfs2(to[e]);
}
set<int>::iterator it;
class Tree{
	#define lc (p<<1)
	#define rc (p<<1|1)
	#define mid (l+r>>1)
	public:
	set<int>c[N<<2];
	inline void pushup(int p){
		for(it=c[lc].begin();it!=c[lc].end();it++)c[p].insert(*it);
		for(it=c[rc].begin();it!=c[rc].end();it++)c[p].insert(*it);
	}
	inline void build(int p,int l,int r){
		if(l==r)return(void)(c[p].insert(a[rev[l]]));
		build(lc,l,mid);
		build(rc,mid+1,r);
		pushup(p);
	}
	inline bool Query(int p,int l,int r,int ql,int qr,int ki){
		if(ql<=l&&r<=qr)return c[p].count(ki);
		bool res=false;
		if(ql<=mid)res=Query(lc,l,mid,ql,qr,ki);
		if(qr>mid)res|=Query(rc,mid+1,r,ql,qr,ki);
		return res;
	}
}T;
inline bool Querylian(int u,int v,int ki){
	bool res=false;
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]])swap(u,v);
		res|=T.Query(1,1,n,id[top[u]],id[u],ki);
		u=fa[top[u]];
	}
	if(dep[u]>dep[v])swap(u,v);
	res|=T.Query(1,1,n,id[u],id[v],ki);
	return res;
}
int main(){
	freopen("visit.in","r",stdin);
	freopen("visit.out","w",stdout);
	n=read(),q=read();
	rep(i,n)a[i]=read();
	int u,v,ki;
	for(int i=1;i<n;i++)u=read(),v=read(),add(u,v),add(v,u);
	dfs1(1,1);
	dfs2(1);
	T.build(1,1,n);
	while(q--){
		u=read(),v=read(),ki=read();
		cout<<Querylian(u,v,ki);
	}
	fclose(stdin);fclose(stdout);
	return 0;
}

T4:

最有意思的题,很妙。

思路是二分答案,然后线段树辅助建图后跑2-SAT板子,tarjan求强联通分量再判断。

2-SAT可以看板子。

洛谷模板

线段树建图待会再说

思路就是对于每一个中心,把它与左右mid范围内的点的对立点连边,连边用线段树建图优化。

每次求强连通分量优化一下。

代码:

#include<bits/stdc++.h>
using namespace std;
#define clear(x) memset(x,0,sizeof (x))
#define op(x) ((x)<=n?(x)+n:(x)-n)

#define mid ((l+r)>>1)
#define ls now*2
#define rs now*2+1

const int N=4e4+10,M=N*20;
int head[N*5],nxt[M],t[M],ec;
void add(int u,int v){
	t[++ec]=v;
	nxt[ec]=head[u];
	head[u]=ec; 
}

struct Flag{
	int pos,id;
	bool operator < (const Flag &f) const {return pos<f.pos;}
	Flag(int pos=0):pos(pos){}
}flgs[N*2];

int n,cnt,id[N*5];

void build(int now,int l,int r){
	id[now]=++cnt;
	if(l==r){
		add(id[now],op(flgs[l].id));//每个点与他的对立点连边
		return ;
	}
	build(ls,l,mid);
	build(rs,mid+1,r);
	add(id[now],id[ls]);
	add(id[now],id[rs]);
}

void link(int now,int l,int r,int x,int y,int point){//对区间连边
	if(y<x) return ;
	if(l==x&&y==r) add(point,id[now]);
	else if(y<=mid) link(ls,l,mid,x,y,point);
	else if(x>mid) link(rs,mid+1,r,x,y,point);
	else link(ls,l,mid,x,mid,point),link(rs,mid+1,r,mid+1,y,point);
}
#undef mid

int dfn[N*5],low[N*5],tim;
int stk[N*5],top;
int scc[N*5],col;
bool in[N*5];

void tarjan(int u){//缩点
	dfn[u]=low[u]=++tim;
	stk[++top]=u;
	in[u]=1;
	for(int i=head[u];i;i=nxt[i]){
		int v=t[i];
		if(!dfn[v]){
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}else {
			if(in[v]){
				low[u]=min(low[u],dfn[v]);
			}
		}
	}
	if(dfn[u]==low[u]){
		++col;
		scc[u]=col;
		while(stk[top]!=u){
			scc[stk[top]]=col;
			in[stk[top]]=0;
			--top;
		}
		in[stk[top]]=0;
		--top;
	}
}

bool check(int v){
	top=tim=ec=0;
	clear(head);
	clear(nxt);
	clear(t);
	clear(dfn);
	clear(low);
	build(1,1,cnt=2*n);
	int l,r;
	for(int i=1;i<=2*n;i++){
		l=upper_bound(flgs+1,flgs+n*2+1,Flag(flgs[i].pos-v))-flgs;//二分查找到左右端点
		r=upper_bound(flgs+1,flgs+n*2+1,Flag(flgs[i].pos+v-1))-flgs-1;
		link(1,1,2*n,l,i-1,flgs[i].id),link(1,1,2*n,i+1,r,flgs[i].id);//左右区间连边
	
	}
	for(int i=1;i<=2*n;i++){
		if(!dfn[i]) tarjan(i);
	}
	for(int i=1;i<=n;i++){
		if(scc[i]==scc[i+n]) return 0;//判断
	}
	return 1;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>flgs[i].pos>>flgs[i+n].pos;
		flgs[i].id=i;
		flgs[i+n].id=i+n;
	}
	sort(flgs+1,flgs+n*2+1);
	int l=0,r=flgs[2*n].pos-flgs[1].pos+1,mid,ans;
	while(l<=r){//二分答案
		mid=(l+r)>>1;
		if(check(mid)) l=mid+1,ans=mid;
		else r=mid-1;
	}
	cout<<ans<<endl;
	return 0;
}
posted @ 2021-11-18 18:48  SSZX_loser_lcy  阅读(45)  评论(0编辑  收藏  举报