模拟17 考试总结

看上去是暴力场,不过依旧炸裂

考试经过

基本操作,看T1,第一眼tarjan,然后自我否定,发现很暴力的样子,于是直接开搜,先套了2个循环,发现跑不出大样例,调半天还是跑不出来,自闭。。。去开T2,
看着像NP完全,果断dfs,,,由于XIN team学的不好觉得可能会假,于是特判上,回来想到T1可以bfs,于是成功过掉大样例收下40。T3没多少时间,上来就测试点分治,乱搞半天,最后40+10+0=50。依旧是少得可怜的分数。。。

T1.世界线

对于每个点,所有他能到的点都要算,再减去已经连的边就是贡献,正解也是这样,用记忆化优化一下,再用bitset砍常数就行了
内存可能会炸,开个池子回收就行了

#include <bits/stdc++.h>
using namespace std;
const int N=100050;
struct node{
	int from,to,next;
}a[2*N];
int head[N],mm=1;
inline void add(int x,int y)
{
	a[mm].from=x;a[mm].to=y;
	a[mm].next=head[x];head[x]=mm++;
}
int b[N],c[N];
int an;queue <int> q;
bitset <60050> v[30050];
int pl[N],p,mp[N],num;
inline void kill(int x)
{
	v[mp[x]].reset();
	pl[++p]=mp[x];
}
inline void newid(int x)
{
	if(p)mp[x]=pl[p--];
	else mp[x]=++num;
}
long long ans;int n,m;
inline void doit()
{
   for(int i=1;i<=n;i++)if(!c[i])q.push(i);
   while(!q.empty())
   {
   	 int x=q.front();if(!mp[x])newid(x);
   	 ans+=v[mp[x]].count()-b[x];
   	 for(int i=head[x];i;i=a[i].next)
   	 {
   	    int y=a[i].to;if(!mp[y])newid(y);
   	    v[mp[y]]|=v[mp[x]];v[mp[y]][x]=1;
   	    c[y]--;if(!c[y])q.push(y);			
	 }
	 kill(x);q.pop();
   }	
}
signed main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
        {
    	  int x,y;scanf("%d%d",&x,&y);
          add(y,x);b[x]++;c[x]++;
	}
	doit();cout<<ans;
	return 0;
}

数据不卡,所以能过,对于极限数据chy使用了一套组合拳完美解决
大意是,卡空间(菊花)就用时间换,卡时间(链)就记搜,遇见蒲公英就一半一半,正好,%%%

T2.时间机器

就是个贪心。。。
把电阻和零件从小到大排序,每次选左端点在他左边的电阻中,右端点最靠左的,正确性显然
用set查后继,用完了就删除,JYF赛事A掉,忒强了

 #include <bits/stdc++.h>
using namespace std;
#define int long long
#define py puts("Yes")
#define pn puts("No")
inline int read()
{
	int x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x;
}
const int N=50050;
struct node{
	int l,r,s,op,id;
	friend bool operator <(node a1,node b1)
	{
		if(a1.r!=b1.r)return a1.r<b1.r;
		else return a1.id>b1.id;
	} 
}a[2*N];
set <node> s;
inline bool cmp(node x,node y)
{
	if(x.l!=y.l)return x.l<y.l;
	else return x.op<y.op;
}
signed main()
{
	int t;cin>>t;
	while(t--)
	{
	  	int n,m;cin>>n>>m;s.clear();
	    for(int i=1;i<=n;i++)a[i].l=read(),a[i].r=read(),a[i].s=read(),a[i].op=1;
	    for(int i=n+1;i<=n+m;i++)a[i].l=read(),a[i].r=read(),a[i].s=read(),a[i].op=0;
        sort(a+1,a+1+n+m,cmp);for(int i=1;i<=n+m;i++)a[i].id=i;
        node sb;sb.r=1e9;sb.id=1e9;s.insert(sb);
        bool flag=0;
        for(int i=1;i<=n+m;i++)
        {
		  if(a[i].op==0)s.insert(a[i]);
    	  else 
    	  while(a[i].s) 
    	  {
    	  	node p=*s.lower_bound(a[i]);
			if(p.r==1e9){flag=1;break;}
    	  	int pp=p.id;int k=min(a[i].s,a[pp].s);
    	  	a[i].s-=k;a[pp].s-=k;
    	  	if(!a[pp].s)s.erase(p);
		  }	
		  if(flag)break;
	    }
	    if(flag)pn;
	    else py;
	} 
	
}  

T3.weight

反正我看不出这是数据结构板子。。。
先求最小生成树,然后分情况讨论:
对于非树边,他的权值最大是他两个端点对应树上最大权值-1,不然一定存在一种方案不选他
对于树边,他会被非树边影响,只要存在一条非树边,那么这两个端点间的所有树边都要比那个非树边的权值减一还小
所以分别对应区间求max,区间取min,树刨就行
用两个线段树分别维护两个操作,不然贼乱虽然这样也很乱
不得不说300行真刺激啊

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=100050;
struct node{
	int from,to,next,w,id,ans;bool ok=0;
	friend bool operator <(node x,node y)
	{
		return x.w>y.w;
	} 
}a[2*N];
priority_queue <node> q;
int head1[N],mm1=1;
inline void add(int x,int y,int z)
{
	a[mm1].from=x;a[mm1].to=y;a[mm1].w=z;a[mm1].id=mm1;
	a[mm1].next=head1[x];q.push(a[mm1]);head1[x]=mm1++;
}
struct newnode{
	int from,to,next,w;
}b[2*N];
int head2[N],mm2=1;
inline void addd(int x,int y,int z)
{
	b[mm2].from=x;b[mm2].to=y;b[mm2].w=z;
	b[mm2].next=head2[x];head2[x]=mm2++;
}
int f[N];int n,m,sb;
inline int find(int x)
{
	if(f[x]!=x)f[x]=find(f[x]);
	return f[x];
}
inline void klskr()
{
	for(int i=1;i<=n;i++)f[i]=i;
	while(!q.empty())
	{
		node nd=q.top();
		int x=nd.from,y=nd.to,w=nd.w;
		if(find(x)!=find(y))
		{
			addd(x,y,w);addd(y,x,w);
			a[nd.id].ok=1;
			f[find(x)]=find(y);
		}
		q.pop();
	}
}
int vis[N],fa[N],son[N],size[N],d[N];
int id[N],rk[N],top[N],cnt,v[N];
inline void dfs1(int x)
{
	vis[x]=1;
	for(int i=head2[x];i;i=b[i].next)
	{
		int y=b[i].to;
		if(vis[y])continue;
		d[y]=d[x]+1;fa[y]=x;
		dfs1(y);
		size[x]+=size[y];
		if(size[y]>size[son[x]])
		 son[x]=y;
	}
	size[x]++;
}
inline void dfs2(int x,int h)
{
    if(!x)return ;
    vis[x]=1;top[x]=h;
    id[x]=++cnt;rk[cnt]=x;
    dfs2(son[x],h);
    for(int i=head2[x];i;i=b[i].next)
    {
    	int y=b[i].to;
    	if(vis[y])continue;
    	if(y==son[x])continue;
    	dfs2(y,y);
    }
}
inline void dfs(int x)
{
	vis[x]=1;
	for(int i=head2[x];i;i=b[i].next)
	{
		int y=b[i].to;
		if(vis[y])continue;
		v[y]=b[i].w;dfs(y);
	}
}
inline int getlca(int x,int y)
{
	int fx=top[x],fy=top[y];
	while(fx!=fy)
	{
		if(d[fx]<d[fy])swap(x,y),swap(fx,fy);
		x=fa[fx];fx=top[x];
	}
	if(id[x]>id[y])swap(x,y);
	return x;
}
struct tree1{
	int l,r,ma;
}tr1[4*N];
inline void build1(int id,int l,int r)
{
	tr1[id].l=l;tr1[id].r=r;
	if(l==r)
	{
		tr1[id].ma=v[rk[l]];
		return;
	}
	int mid=(l+r)>>1;
	build1(id*2,l,mid);build1(id*2+1,mid+1,r);
	tr1[id].ma=max(tr1[id*2].ma,tr1[id*2+1].ma); 
}
inline void change1(int id,int p,int v)
{
	if(tr1[id].l==tr1[id].r)
	{
		tr1[id].ma=v;
		return;
	}
	int mid=(tr1[id].l+tr1[id].r)>>1;
	if(p<=mid)change1(id*2,p,v);
	else change1(id*2+1,p,v);
	tr1[id].ma=max(tr1[id*2].ma,tr1[id*2+1].ma);
}
inline int getmax(int id,int l,int r)
{
	if(l<=tr1[id].l&&r>=tr1[id].r)return tr1[id].ma;
	int mid=(tr1[id].l+tr1[id].r)>>1;
	if(r<=mid)return getmax(id*2,l,r);
	if(l>mid)return getmax(id*2+1,l,r);
	return max(getmax(id*2,l,mid),getmax(id*2+1,mid+1,r)); 
}
struct tree2{
	int l,r,mi,lazy=-1;
}tr2[4*N];
inline void build2(int id,int l,int r)
{
	tr2[id].l=l;tr2[id].r=r;
        if(l==r)
        {
    	  tr2[id].mi=1e12;
    	  tr2[id].lazy=1e12;
    	  return;
	}
	int mid=(l+r)>>1;
	build2(id*2,l,mid);build2(id*2+1,mid+1,r);
	tr2[id].lazy=1e12;
	tr2[id].mi=min(tr2[id*2].mi,tr2[id*2+1].mi);
}
inline void luo(int id)
{
	if(tr2[id].lazy!=1e12&&tr2[id].l!=tr2[id].r)
	{
	   tr2[id*2].lazy=min(tr2[id*2].lazy,tr2[id].lazy);
	   tr2[id*2+1].lazy=min(tr2[id*2+1].lazy,tr2[id].lazy);
	   tr2[id*2].mi=min(tr2[id*2].mi,tr2[id].lazy);
	   tr2[id*2+1].mi=min(tr2[id*2+1].mi,tr2[id].lazy);
	   tr2[id].lazy=1e12;   
	}	 
}
inline void change2(int id,int p,int v)
{
        if(tr2[id].l==tr2[id].r)
	{
	  tr2[id].mi=v;
	  return;	
	}	
	luo(id);
	int mid=(tr2[id].l+tr2[id].r)>>1;
	if(p<=mid)change2(id*2,p,v);
	else change2(id*2+1,p,v);
	tr2[id].mi=min(tr2[id*2].mi,tr2[id*2+1].mi);
} 
inline int getmin(int id,int l,int r)
{
        if(l<=tr2[id].l&&r>=tr2[id].r)return tr2[id].mi;
	luo(id);int mid=(tr2[id].l+tr2[id].r)>>1;
	if(r<=mid)return getmin(id*2,l,r);
	if(l>mid)return getmin(id*2+1,l,r);
	return min(getmin(id*2,l,mid),getmin(id*2+1,mid+1,r));	
}  
inline void domin(int id,int l,int r,int v)
{
	if(l<=tr2[id].l&&r>=tr2[id].r)
	{
		tr2[id].lazy=min(tr2[id].lazy,v);
		tr2[id].mi=min(tr2[id].mi,v);
		return;
	}
	luo(id);int mid=(tr2[id].l+tr2[id].r)>>1;
	if(r<=mid)domin(id*2,l,r,v);
	else if(l>mid)domin(id*2+1,l,r,v);
	else domin(id*2,l,r,v),domin(id*2+1,l,r,v);
	tr2[id].mi=min(tr2[id*2].mi,tr2[id*2+1].mi);
}
inline int ganmax(int x,int y)
{
	int ans=0,fx=top[x],fy=top[y];
	while(fx!=fy)
        {
    	  if(d[fx]<d[fy])swap(x,y),swap(fx,fy);
    	  ans=max(ans,getmax(1,id[fx],id[x]));
    	  x=fa[fx];fx=top[x];
	}
	if(id[x]>id[y])swap(x,y);
	ans=max(ans,getmax(1,id[x],id[y]));
	return ans;
} 
inline void gan(int x,int y,int v)
{
	int fx=top[x],fy=top[y];
	while(fx!=fy)
        {
    	 if(d[fx]<d[fy])swap(x,y),swap(fx,fy);
    	 domin(1,id[fx],id[x],v);
    	 x=fa[fx];fx=top[x];
	}
	if(id[x]>id[y])swap(x,y);
        domin(1,id[x],id[y],v);
} 
signed main()
{
	cin>>n>>m>>sb;
	for(int i=1;i<=m;i++)
        {
    	  int x,y,z;scanf("%lld%lld%lld",&x,&y,&z);
	  add(x,y,z);
	}
	klskr();d[1]=1;dfs1(1);	 
	memset(vis,0,sizeof(vis));dfs2(1,1);
	memset(vis,0,sizeof(vis));dfs(1);
        build1(1,1,cnt);build2(1,1,cnt);
	for(int i=1;i<mm1;i++)
	{
		if(!a[i].ok)
		{
			int x=a[i].from,y=a[i].to;
			int lca=getlca(x,y),p=getmax(1,id[lca],id[lca]);
			change1(1,id[lca],-1e9);
			a[i].ans=ganmax(x,y)-1;
			change1(1,id[lca],p);
			int pp=getmin(1,id[lca],id[lca]);
			gan(x,y,a[i].w-1);change2(1,id[lca],pp); 
		}
	}
	for(int i=1;i<mm1;i++)
	{
		if(a[i].ok)
		{
			int x=a[i].from,y=a[i].to;
			if(d[x]<d[y])swap(x,y);
			a[i].ans=getmin(1,id[x],id[x]); 
			if(a[i].ans==1e12)a[i].ans=-1;
		} 
	}
	for(int i=1;i<mm1;i++)printf("%lld ",a[i].ans); 
	return 0;
}  

怪吓人的
对于区间取min,由于你只维护min值,所以直接打标记就行了

考试总结

1.对于T1这种,要有意识的优化,很可能暴力差一步就是正解
2.看见T2这种就要有贪心的敏感,要相信题是可做的,别自我放弃
3.打部分分要么打稳,要么就别打,沉迷测试点分治一旦失败就跟爆零没啥区别了

posted @ 2021-07-24 18:09  D'A'T  阅读(61)  评论(0)    收藏  举报