noip模拟17[世界线·时间机器·weight]

noip模拟17 solutions

从开始考我就意识到这次考不好了,为啥呢?因为正常考试我连交题的欲望都没有

一共交了\(4\)遍,果不其然,\(30pts\)非常愉快的拿到了第二题的暴力分

最大的错误就是两个小时的时候,我连电脑都没碰一下,说白了还是时间分配问题,下次注意

记录一下,JYXHYX又考场A题了,我天呐,太强了

·

T1 世界线

不得不说,这个题吧,让人很有做它的欲望,但是你做着做着就觉得好像完全没有思路,

就这个,我一会想着要用并查集,一会想着要递推,一会又想着要\(dfs\),到最后也没想到正解

但是打暴力还是很重要的,这个题本身就是一个\(bitset\)优化的\(dfs\),万能的\(STL!!!\)

仔细研究研究题意你就会发现,这个连边是有传递性的,一个点会和他的所有后代都连上,他要连的边,就是他的后代数减去他的出度

所以我们如何维护他有多少后代呢,其实这个题dfs完全可以解决,完全不需要拓扑排序,

我们知道\(bitset\)可以进行基本的位运算,还可以统计1的个数,所以我只要把所有的儿子标记为1,然后不停向上合并就好了

\(bitset\)中存的就是,当前的所有后代

但是我们发现,我们根本无法存下\(N*N\)\(bitset\),即使它一位只占用1/8字节,也就是一字,也就是int的1/32;

那我们就分成10次来算,因为你发现每一个之间是互不影响的

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=6e4+50;
const int M=1e5+5;
int n,m,l,r;
int to[M],nxt[M],head[N],rp;
void add_edg(int x,int y){
	to[++rp]=y;
	nxt[rp]=head[x];
	head[x]=rp;
}
bitset<N/10> b[N];
int ans[N],cdu[N],rdu[N];
bool vis[N];
void dfs(int x){
	//cout<<x<<endl;
	vis[x]=true;
	for(re i=head[x];i;i=nxt[i]){
		int y=to[i];
		if(y>=l&&y<=r)b[x].set(y-l);
		if(vis[y]==false)dfs(y);
		b[x]=b[x]|b[y];
	}
	//ans[x]+=b[x].count();
	//cout<<x<<" "<<ans[x]<<endl;
}
int anss;
signed main(){
	scanf("%d%d",&n,&m);
	for(re i=1,x,y;i<=m;i++){
		scanf("%d%d",&x,&y);
		add_edg(x,y);
		rdu[y]++;cdu[x]++;
	}
	l=1,r=min(6000,n);
	while(l<=n){
		//cout<<l<<" "<<r<<endl;
		memset(vis,false,sizeof(vis));
		for(re i=1;i<=n;i++)b[i].reset();
		for(re i=1;i<=n;i++)if(!rdu[i])dfs(i);//cout<<i<<endl;
		for(re i=1;i<=n;i++)ans[i]+=b[i].count();
		l=r+1;r=min(l+6000-1,n);
	}
	for(re i=1;i<=n;i++){
		anss+=(ans[i]-cdu[i]);
		//cout<<i<<" "<<ans[i]<<" "<<cdu[i]<<endl;
	}
	printf("%d",anss);
}

·

T2 时间机器

这个明显一眼就是贪心,是的没错

而我,考场上想到贪心却不知道怎么维护,然后就直接跳过了,所以没拿分;

他们说这个是最经典的覆盖问题

所以我们按照左端点右端点,双关键字排序,然后插入到set中

这样我们每次都可以查询左端点在左边,右端点距离它最近的了

注意set只按照右端点排序,就是重载运算符只比较右端点,左端点在插入时就维护好了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=5e4+5;
int T,n,m;
struct node{
	int l,r,k,id;
	bool operator < (node x)const{
		return x.r>r;
	}
}dot[N],omu[N];
set<node> st;
set<node>::iterator it,pd;
int szd[N],szo[N];
int cnt;
node ji[N];
bool cmp(node x,node y){
	return x.l<y.l;
}
signed main(){
	scanf("%d",&T);
	while(T--){
		st.clear();
		scanf("%d%d",&n,&m);
		for(re i=1;i<=n;i++){
			scanf("%d%d%d",&dot[i].l,&dot[i].r,&dot[i].k);
			dot[i].id=i;szd[i]=dot[i].k;
		}
		for(re i=1;i<=m;i++){
			scanf("%d%d%d",&omu[i].l,&omu[i].r,&omu[i].k);
			omu[i].id=i;szo[i]=omu[i].k;
		}
		sort(dot+1,dot+n+1,cmp);
		//cout<<dot[1].r<<endl;
		sort(omu+1,omu+m+1,cmp);
		int j=1,flag=0;
		for(re i=1;i<=n;i++){
			cnt=0;
			for(;j<=m&&omu[j].l<=dot[i].l;j++){
				pd=st.find(omu[j]);
				if(pd!=st.end()){
					szo[(*pd).id]+=szo[omu[j].id];
					continue;
				}
				st.insert(omu[j]);
			}
			//cout<<j<<endl;
			pd=st.find(dot[i]);
			if(pd!=st.end()){
				if(szo[(*pd).id]>=szd[dot[i].id]){
					szo[(*pd).id]-=szd[dot[i].id];
					szd[dot[i].id]=0;
					if(szo[(*pd).id]==0)st.erase((*pd));
					continue;
				}
				szd[dot[i].id]-=szo[(*pd).id];
				szo[(*pd).id]=0;
				st.erase((*pd));
			}
			st.insert(dot[i]);
			it=st.find(dot[i]);
			while(szd[dot[i].id]){
				it++;//cout<<(*it).r<<" "<<(*it).id<<endl;
				if(it==st.end()){
					flag=1;break;
				}
				if(szd[dot[i].id]>=szo[(*it).id]){
					szd[dot[i].id]-=szo[(*it).id];
					szo[(*it).id]=0;
					ji[++cnt]=(*it);
				}
				else{
					szo[(*it).id]-=szd[dot[i].id];
					szd[dot[i].id]=0;
				}
			}
			if(flag==1){
				printf("No\n");break;
			}
			st.erase(dot[i]);
			for(re i=1;i<=cnt;i++)st.erase(ji[i]);
		}
		if(!flag)printf("Yes\n");
	}
}

·

T3 weight

所以这个题真的是最小生成树

然后听到这个消息之后,我没看题解就吧这个题A掉了,我太强了

哈哈哈,就是我们先找到最小生成树,记录那些是最小生成树中的边,哪些是非树边

对最小生成树进行树链剖分,我们利用非树边在他两个端点之间的路径上跑

更新树边的最大值,反过来继续更新自己

判断是否和1联通在最小生成树的时候用并查集维护就好啦

AC_code


#include<bits/stdc++.h>
using namespace std;
#define re register int 
const int N=7e5+5;
const int M=1e6+5;
const int inf=0x3f3f3f3f;
int n,m,ans[N];
int to[M*2],nxt[M*2],val[M*2],id[M*2],head[N],rp;
void add_edg(int x,int y,int z,int i){
	to[++rp]=y;
	val[rp]=z;
	id[rp]=i;
	nxt[rp]=head[x];
	head[x]=rp;
}
struct EDGE{
	int fr,to,val,id,typ;
	bool operator < (EDGE x)const{
		return x.val>val;
	}
}edg[M];
int fai[N],si[N],rt,sz;
int find(int x){return x==fai[x]?x:fai[x]=find(fai[x]);}
void klus(){
	sort(edg+1,edg+m+1);
	for(re i=1;i<=n;i++)fai[i]=i,si[i]=1;
	int sum=0;
	for(re i=1;i<=m;i++){
		int x=edg[i].fr,y=edg[i].to;
		int fx=find(x),fy=find(y);
		if(fx==fy)continue;
		fai[fx]=fy;sum++;si[fy]+=si[fx];
		edg[i].typ=1;
		add_edg(x,y,edg[i].val,edg[i].id);
		add_edg(y,x,edg[i].val,edg[i].id);
		//if(sum==n-1)break;
	}
	rt=find(1);sz=si[rt];
}
int pval[N],idf[N];
int ifd[N];
struct seg_tree{
	#define ls x<<1
	#define rs x<<1|1
	int maxn[N*4],laz[N*4],va[N*4];
	/*seg_tree(){
		memset(maxn,0x3f,sizeof(maxn));
		memset(laz,0x3f,sizeof(laz));
	}*/
	void build(int x,int l,int r){
		maxn[x]=inf;laz[x]=inf;
		if(l==r){
			va[x]=pval[ifd[l]];
			return ;
		}
		int mid=l+r>>1;
		build(ls,l,mid);
		build(rs,mid+1,r);
		va[x]=max(va[ls],va[rs]);
		return ;
	}
	inline void pushdown(int x){
		if(laz[x]==inf)return ;
		laz[ls]=min(laz[ls],laz[x]);
		maxn[ls]=min(maxn[ls],laz[x]);
		laz[rs]=min(laz[rs],laz[x]);
		maxn[rs]=min(maxn[rs],laz[x]);
		laz[x]=inf;
		return ;
	}
	void update(int x,int l,int r,int ql,int qr,int v){
		if(ql>qr)return ;
		if(ql<=l&&r<=qr){
			laz[x]=min(laz[x],v);
			maxn[x]=min(maxn[x],v);
			return ;
		}
		pushdown(x);
		int mid=l+r>>1;
		if(ql<=mid)update(ls,l,mid,ql,qr,v);
		if(qr>mid)update(rs,mid+1,r,ql,qr,v);
		return ;
	}
	int query(int x,int l,int r,int pos){
		if(l==r)return maxn[x]==inf?-1:maxn[x];
		pushdown(x);
		int mid=l+r>>1;
		if(pos<=mid)return query(ls,l,mid,pos);
		else return query(rs,mid+1,r,pos);
	}
	int query_re(int x,int l,int r,int ql,int qr){
		if(ql>qr)return 0;
		if(ql<=l&&r<=qr)return va[x];
		int mid=l+r>>1,ret=0;
		if(ql<=mid)ret=max(ret,query_re(ls,l,mid,ql,qr));
		if(qr>mid)ret=max(ret,query_re(rs,mid+1,r,ql,qr));
		return ret;
	}
	#undef ls
	#undef rs
}xds;
int dfn[N],cnt,fa[N];
int siz[N],son[N],rak[N],top[N],dep[N];
void dfs1(int x){
	siz[x]=1;son[x]=0;
	for(re i=head[x];i;i=nxt[i]){
		int y=to[i];
		if(y==fa[x])continue;
		fa[y]=x;dep[y]=dep[x]+1;
		dfs1(y);siz[x]+=siz[y];
		if(!son[x]||siz[y]>siz[son[x]])son[x]=y,rak[x]=i;
	}
}
void dfs2(int x,int f){
	dfn[x]=++cnt;top[x]=f;
	ifd[cnt]=x;
	if(son[x]){
		pval[son[x]]=val[rak[x]];
		idf[id[rak[x]]]=son[x];
		dfs2(son[x],f);
	}
	for(re i=head[x];i;i=nxt[i]){
		int y=to[i];
		if(y==son[x]||y==fa[x])continue;
		pval[y]=val[i];idf[id[i]]=y;
		dfs2(y,y);
	}
}
void change(int x,int y,int v,int i){
	if(top[x]==0||top[y]==0)return ;
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		xds.update(1,1,cnt,dfn[top[x]],dfn[x],v);
		ans[i]=max(ans[i],xds.query_re(1,1,cnt,dfn[top[x]],dfn[x])-1);
		x=fa[top[x]];
	}
	//if(x==y)return ;
	if(dep[x]<dep[y])swap(x,y);
	//cout<<dep[x]<<" "<<dfn[x]<<" "<<dep[y]<<" "<<dfn[y]<<endl;
	xds.update(1,1,cnt,dfn[y]+1,dfn[x],v);
	ans[i]=max(ans[i],xds.query_re(1,1,cnt,dfn[y]+1,dfn[x])-1);
}
bool cmp(EDGE x,EDGE y){
	return x.id<y.id;
}
signed main(){
	int ooo;scanf("%d%d%d",&n,&m,&ooo);
	for(re i=1;i<=m;i++){
		scanf("%d%d%d",&edg[i].fr,&edg[i].to,&edg[i].val);
		edg[i].id=i;
	}
	klus();dep[1]=1;
	dfs1(1);dfs2(1,1);
	xds.build(1,1,cnt);
	sort(edg+1,edg+m+1,cmp);
	for(re i=1;i<=m;i++){
		if(edg[i].typ==1)continue;
		//cout<<edg[i].val<<" "<<edg[i].fr<<" "<<edg[i].to<<endl;
		ans[i]=0;change(edg[i].fr,edg[i].to,edg[i].val-1,i);
	}
	for(re i=1;i<=m;i++){
		//cout<<edg[i].typ<<" ";
		if(find(edg[i].fr)!=rt||find(edg[i].to)!=rt)ans[i]=0,edg[i].typ=0;
		if(edg[i].typ==1){
			//cout<<idf[i]<<endl;
			ans[i]=xds.query(1,1,cnt,dfn[idf[i]]);
		}
		printf("%d ",ans[i]);
	}
}
posted @ 2021-07-18 20:17  fengwu2005  阅读(69)  评论(0编辑  收藏  举报