2020.09.05【省选组】模拟 比赛总结

题目

T1 仙人图(II)

Description

如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人图(cactus)。所谓简单回路就是指在图上不重复经过任何一个顶点的回路。
在这里插入图片描述

举例来说,上面的第一个例子是一张仙人图,而第二个不是——注意到它有三条简单回路:(4,3,2,1,6,5,4)、(7,8,9,10,2,3,7)以及(4,3,7,8,9,10,2,1,6,5,4),而(2,3)同时出现在前两个的简单回路里。另外,第三张图也不是仙人图,因为它并不是连通图。
显然,仙人图上的每条边,或者是这张仙人图的桥(bridge),或者在且仅在一个简单回路里,两者必居其一。定义在图上两点之间的距离为这两点之间最短路径的距离。定义一个图的直径为这张图相距最远的两个点的距离。现在我们假定仙人图的每条边的权值都是1,你的任务是求出给定的仙人图的直径。

Input

输入的第一行包括两个整数n和m(1≤n≤50,000以及0≤m≤10,000)。其中n代表顶点个数,我们约定图中的顶点将从1到n编号。
接下来一共有m行。代表m条路径。每行的开始有一个整数k(2≤k≤1000),代表在这条路径上的顶点个数。接下来是k个1到n之间的整数,分别对应了一个顶点,相邻的顶点表示存在一条连接这两个顶点的边。一条路径上可能通过一个顶点好几次,比如对于第一个样例,第一条路径从3经过8,又从8返回到了3,但是我们保证所有的边都会出现在某条路径上,而且不会重复出现在两条路径上,或者在一条路径上出现两次。

Output

只需输出一个数,这个数表示仙人图的直径长度。

Sample Input

15 3
9 1 2 3 4 5 6 7 8 3
7 2 9 10 11 12 13 10
5 2 14 9 15 10

Sample Output

8

Hint

样例解释:
在这里插入图片描述


T2 Prime的把妹计划

Description

在这里插入图片描述

Input

在这里插入图片描述

Output

在这里插入图片描述

Sample Input

在这里插入图片描述

Sample Output

在这里插入图片描述

Data Constraint

在这里插入图片描述


T3 Segment

Description

要求在平面直角坐标系下维护两个操作:

  1. 在平面上加入一条线段。记第 i条被插入的线段标号为 i。
  2. 给定一个数 k,询问与直线 x = k相交的线段中,交点最靠上的线段的编号。

Input

在这里插入图片描述

Output

对于每个 0操作,输出一行,包含一个正整数,表示交点最靠上的线段的编号。若不存在与直线相交的段,答案为 0。

Sample Input

6
1 8 5 10 8
1 6 7 2 6
0 2
0 9
1 4 7 6 7
0 5

Sample Output

2
0
3

Data Constraint

对于 30% 的数据, n ≤ 1000
对于 100% 的数据, 1 ≤ n ≤ 10^5, 1 ≤ k, x0, x1 ≤ 39989, 1 ≤ y0 ≤ y1 ≤ 10^9。


总结

高中阶段的第一场比赛
早上要做大扫除,晚到一个小时感觉真不好……


T1
看到仙人掌,一眼圆方树。
做成一棵树之后DP即可,还是老套路,设 f i f_i fi表示以 i 为根的子树中以 i 为一端的路径的最大长度, g i g_i gi表示以 i 为根的子树的直径长度。
然而发现方点要特殊处理。
在树上处理起来太麻烦了,于是把环拉成一个序列,设 h i h_i hi表示在环上顺时针数第 i-1 个点的 f 值(不考虑第一个点,即成为方点的父亲的那个点)。
然后就可以写出状态转移方程了(G是当前要更新的那个点的g,siz表示环的大小)
G = max ⁡ ( h i + h j + min ⁡ ( j − i , s i z − j + i ) ) , 1 < i < j ≤ s i z G=\max(h_i+h_j+\min(j-i,siz-j+i)),1<i<j\leq siz G=max(hi+hj+min(ji,sizj+i)),1<i<jsiz
但是这样子优化不了DP,那个min实在是太难受了。
于是把原来的序列再重复一遍(注意留一个空的位置给第一个点),这样子状态转移方程就变成这个样子了:
G = max ⁡ ( h i + h j + j − i ) , 1 < i < j ≤ s i z , j − i ≤ ⌊ s i z 2 ⌋ G=\max(h_i+h_j+j-i),1<i<j\leq siz,j-i\leq\left \lfloor\frac{siz}{2}\right \rfloor G=max(hi+hj+ji),1<i<jsiz,ji2siz
单调队列优化即可。
想不到我第一次打圆方树(还是在考场上打)居然能切题!


T2
考场上打了个 O ( n 2 ) O(n^2) O(n2)暴力,居然WA 5了,心态大崩。
以下是SLS大佬的分块做法:
发现n只有50000,而且时间限制是4s,可以分块。
先考虑 ∀ l ≤ i ≤ r , a l ≥ a i ≥ a r \forall l\leq i\leq r,a_l\geq a_i\geq a_r lir,alaiar的情况。
定义 l i l_i li表示以 i 为“艄”序列的右端点,左端点最小是多少, r i r_i ri表示以 i 为“艄”序列的左端点,右端点最大是多少。这两个东西都可以用单调栈快速地求出来。
接着把 [ 1 , n ] [1,n] [1,n]分成 n \sqrt{n} n 块,设 f i , j f_{i,j} fi,j表示第 i 块的左端点到第 j 块的右端点中最长的“艄”序列的长度。那么
f i , j = { f i , j − 1 , min ⁡ l j j i , r i ≥ j f_{i,j}= \begin{cases} f_{i,j-1},\\ \min_{l_j}^j i,r_i\geq j \end{cases} fi,j={ fi,j1,minljji,rij
min那里可以用线段树求,最后倒过来再搞一次就好了。
时间复杂度 O ( n n log ⁡ 2 n ) O(n\sqrt n \log_2n) O(nn log2n)
虽然码量较大,但是没什么细节。


T3
李超树板题。
考场上想怎么把直线扔到线段树上处理,结果发现好像要维护一个长得很奇怪的图形。
其实是我对线段树理解不够深,利用线段树递归logN层,把大小为N的区间划分为大小为1的区间的特点可以大搞事情。
每个点上都维护一个标记表示当前区间里的所有线段中,k*mid+b最大的那条线段。
如果被替换掉的线段(或者是替换失败的线段)在当前区间中某段比替换成功的线段要优,可以继续递归下去;否则就没有递归下去的意义了。
最后单点查询时一路更新答案即可。

总结
暴力正确率不够,不是模拟的分值较高的暴力一定要对拍。


CODE

T1

#include<cstdio>
using namespace std;
#define M 200005
#define N 100005
struct graph
{
    
    
	int fir[N],to[M],nex[M],s;
	inline void inc(int x,int y)
	{
    
    
		to[++s]=y,nex[s]=fir[x],fir[x]=s;
		to[++s]=x,nex[s]=fir[y],fir[y]=s;
	}
}a;
int que[N],f[N],g[N],h[N],fir[N],to[N],nex[N],len[N],dfn[N],low[N],dis[N],sta[N],ord[N],n,s,top,cnt,node;
inline char gc()
{
    
    
	static char buf[100005],*l=buf,*r=buf;
	return l==r&&(r=(l=buf)+fread(buf,1,100005,stdin),l==r)?EOF:*l++;
}
inline void read(int &k)
{
    
    
	char ch;
	while(ch=gc(),ch<'0'||ch>'9');k=ch-'0';
	while(ch=gc(),ch>='0'&&ch<='9') k=k*10+ch-'0';
}
inline void inc(int x,int y,int z)
{
    
    to[++s]=y,len[s]=z,nex[s]=fir[x],fir[x]=s;}
inline int mymin(int x,int y){
    
    return x<y?x:y;}
inline int mymax(int x,int y){
    
    return x>y?x:y;}
void tarjan(int u)
{
    
    
	int x,v,i,sum,num;
	dfn[u]=low[u]=++cnt,sta[++top]=u;
	for(i=a.fir[u];i;i=a.nex[i])
	{
    
    
		v=a.to[i];
		if(!dfn[v])
		{
    
    
			dis[v]=dis[u]+1;
			tarjan(v);
			if(low[u]>low[v]) low[u]=low[v];
			if(low[v]==dfn[u])
			{
    
    
				inc(u,++node,0);
				sum=dis[sta[top]]-dis[u]+1;
				for(x=0;x!=v;--top)
				{
    
    
					x=sta[top];
					ord[x]=dis[x]-dis[u];
					inc(node,x,mymin(ord[x],sum-ord[x]));
				}
			}
		}
		else if(low[u]>dfn[v]) low[u]=dfn[v];
	}
}
void dfs(int u)
{
    
    
	int i,v;
	for(i=fir[u];i;i=nex[i])
	{
    
    
		v=to[i],dfs(v);
		if(g[v]>g[u]) g[u]=g[v];
		if(f[v]+len[i]>f[u]) f[u]=f[v]+len[i];
	}
	if(u>n)
	{
    
    
		int siz=0,head=1,tail=1,max;
		for(i=fir[u];i;i=nex[i])
		{
    
    
			v=to[i],h[ord[v]]=f[v];
			if(ord[v]>siz) siz=ord[v];
		}
		++siz,max=siz>>1;
		que[1]=1,h[siz+1]=h[1];
		for(i=2;i<siz;++i)
		{
    
    
			h[siz+i]=h[i];
			while(i-que[head]>max) ++head;
			g[u]=mymax(g[u],h[i]+h[que[head]]+i-que[head]);
			while(head<=tail&&h[que[tail]]-que[tail]<=h[i]-i) --tail;
			que[++tail]=i;
		}
		for(i=siz+1;i<siz+max;++i)
		{
    
    
			while(i-que[head]>max) ++head;
			g[u]=mymax(g[u],h[i]+h[que[head]]+i-que[head]);
		}
	}
	else
	{
    
    
		int max1=0,max2=0;
		for(i=fir[u];i;i=nex[i])
		{
    
    
			v=to[i];
			if(f[v]>max1) max2=max1,max1=f[v];
			else if(f[v]>max2) max2=f[v];
		}
		if(g[u]<max1+max2) g[u]=max1+max2;
	}
	if(g[u]<f[u]) g[u]=f[u];
}
int main()
{
    
    
	int m,k,x,y;
	read(n),read(m),node=n;
	for(int i=1;i<=m;++i)
	{
    
    
		read(k),read(y);
		for(int j=2;j<=k;++j) read(x),a.inc(x,y),y=x;
	}
	tarjan(1),dfs(1);
	printf("%d\n",g[1]);
	return 0;
}

T2

#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define rson k<<1|1
#define lson k<<1
#define N 50005
struct query{
    
    int x,y,ans;}qry[N];
int a[N],left[N],right[N],sta[N],max[250005],min[250005],f[235][235],fir[235],n,q,siz,tot;
inline char gc()
{
    
    
	static char buf[50005],*l=buf,*r=buf;
	return l==r&&(r=(l=buf)+fread(buf,1,50005,stdin),l==r)?EOF:*l++;
}
inline void read(int &k)
{
    
    
	char ch;
	while(ch=gc(),ch<'0'||ch>'9');k=ch-'0';
	while(ch=gc(),ch>='0'&&ch<='9') k=k*10+ch-'0';
}
inline int mymax(int x,int y){
    
    return x>y?x:y;}
inline int mymin(int x,int y){
    
    return x<y?x:y;}
void build(int k,int l,int r)
{
    
    
	if(l==r) max[k]=right[l],min[k]=left[l];
	else
	{
    
    
		int mid=l+r>>1;
		build(lson,l,mid);
		build(rson,mid+1,r);
		max[k]=mymax(max[lson],max[rson]);
		min[k]=mymin(min[lson],min[rson]);
	}
}
int qrymax(int k,int l,int r,int x,int y,int z)
{
    
    
	if(max[k]<=z) return 0;
	if(l==r) return l;
	int mid=l+r>>1,tmp;
	if(y<=mid) return qrymax(lson,l,mid,x,y,z);
	if(x>mid) return qrymax(rson,mid+1,r,x,y,z);
	tmp=qrymax(lson,l,mid,x,mid,z);
	return tmp?tmp:qrymax(rson,mid+1,r,mid+1,y,z);
}
int qrymin(int k,int l,int r,int x,int y,int z)
{
    
    
	if(min[k]>z) return 0;
	if(l==r) return l;
	int mid=l+r>>1,tmp;
	if(y<=mid) return qrymin(lson,l,mid,x,y,z);
	if(x>mid) return qrymin(rson,mid+1,r,x,y,z);
	tmp=qrymin(rson,mid+1,r,mid+1,y,z);
	return tmp?tmp:qrymin(lson,l,mid,x,mid,z);
}
inline void calc()
{
    
    
	build(1,1,n);
	memset(f,0,sizeof(f));
	for(int i=1;i<=tot;++i)
		for(int j=fir[i];j<fir[i+1];++j)
			f[i][i]=mymax(f[i][i],j-qrymax(1,1,n,mymax(left[j]+1,fir[i]),j,j)+1);
	for(int len=1;len<tot;++len)
		for(int i=1,j=len+1;j<=tot;++i,++j)
		{
    
    
			f[i][j]=f[i][j-1];
			for(int k=fir[j];k<fir[j+1];++k)
				f[i][j]=mymax(f[i][j],k-qrymax(1,1,n,mymax(left[k]+1,fir[i]),k,k)+1);
		}
	for(int i=1,ans,l,r;i<=q;++i)
	{
    
    
		ans=0;
		l=(qry[i].x-1)/siz+1;
		r=(qry[i].y-1)/siz+1;
		if(qry[i].y<fir[r+1]-1)
			for(int j=fir[r--];j<=qry[i].y;++j) ans=mymax(ans,j-qrymax(1,1,n,mymax(left[j]+1,qry[i].x),j,j)+1);
		if(qry[i].x>fir[l])
		{
    
    
			++l;
			if(f[l][r]>ans) ans=f[l][r];
			for(int j=qry[i].x;j<fir[l];++j) ans=mymax(ans,qrymin(1,1,n,j,mymin(right[j]-1,qry[i].y),j)-j+1);
		}
		else if(f[l][r]>ans) ans=f[l][r];
		if(ans>qry[i].ans) qry[i].ans=ans;
	}
}
int main()
{
    
    
	int i,j,x,y,top;
	read(n),siz=sqrt(n);
	tot=n/siz;if(tot*siz<n) ++tot;
	for(i=1;i<=tot;++i) fir[i]=(i-1)*siz+1;
	fir[tot+1]=n+1;
	for(i=1;i<=n;++i) read(a[i]);
	read(q);
	for(i=1;i<=q;++i) read(qry[i].x),read(qry[i].y);
	for(i=1,top=0;i<=n;++i)
	{
    
    
		while(top&&a[i]<=a[sta[top]]) --top;
		left[i]=sta[top],sta[++top]=i;
	}
	for(i=n,top=0;i;--i)
	{
    
    
		while(top&&a[i]>=a[sta[top]]) --top;
		right[i]=top?sta[top]:n+1,sta[++top]=i;
	}
	calc();
	for(i=1,top=0;i<=n;++i)
	{
    
    
		while(top&&a[i]>=a[sta[top]]) --top;
		left[i]=sta[top],sta[++top]=i;
	}
	for(i=n,top=0;i;--i)
	{
    
    
		while(top&&a[i]<=a[sta[top]]) --top;
		right[i]=top?sta[top]:n+1,sta[++top]=i;
	}
	calc();
	for(i=1;i<=q;++i) printf("%d\n",qry[i].ans);
	return 0;
}

T3

#include<cstdio>
using namespace std;
#define lson k<<1
#define rson k<<1|1
#define P2 1000000000
#define P1 39989
#define N 100005
inline char gc()
{
    
    
	static char buf[100005],*l=buf,*r=buf;
	return l==r&&(r=(l=buf)+fread(buf,1,100005,stdin),l==r)?EOF:*l++;
}
inline void read(int &k)
{
    
    
	char ch;
	while(ch=gc(),ch<'0'||ch>'9');k=ch-'0';
	while(ch=gc(),ch>='0'&&ch<='9') k=k*10+ch-'0';
}
int tag[500005],ans;double top;
struct line{
    
    int l,r;double k,b;}a[N];
inline void swap(int &x,int &y){
    
    int z=x;x=y,y=z;}
inline double calc(int k,int x){
    
    return x*a[k].k+a[k].b;}
void modify(int k,int l,int r,int x)
{
    
    
	if(a[x].l<=l&&r<=a[x].r)
	{
    
    
		if(!tag[k]) tag[k]=x;
		else
		{
    
    
			bool b1=calc(tag[k],l)<calc(x,l),b2=calc(tag[k],r)<calc(x,r);
			if(b1&&b2) tag[k]=x;
			else if(b1||b2)
			{
    
    
				int mid=l+r>>1;
				if(calc(tag[k],mid)<calc(x,mid)) swap(tag[k],x);
				if(calc(tag[k],l)<calc(x,l)) modify(lson,l,mid,x);
				else modify(rson,mid+1,r,x);
			}
		}
	}
	else
	{
    
    
		int mid=l+r>>1;
		if(a[x].l<=mid) modify(lson,l,mid,x);
		if(a[x].r>mid) modify(rson,mid+1,r,x);
	}
}
void qry(int k,int l,int r,int x)
{
    
    
	if(tag[k]&&(top<calc(tag[k],x)||top==calc(tag[k],x)&&tag[k]<ans)) top=calc(tag[k],x),ans=tag[k];
	if(l==r) return;
	int mid=l+r>>1;
	if(x<=mid) qry(lson,l,mid,x);
	else qry(rson,mid+1,r,x);
}
int main()
{
    
    
	int n,i,j,cnt=0,opt,x0,y0,x1,y1,x;
	double k;
	read(n);
	for(i=1;i<=n;++i)
	{
    
    
		read(opt);
		if(opt==0)
		{
    
    
			read(x),x=(x+ans-1)%P1+1;
			top=0,ans=0,qry(1,1,P1,x);
			printf("%d\n",ans);
		}
		else
		{
    
    
			read(x0),read(y0),read(x1),read(y1);
			x0=(x0+ans-1)%P1+1,y0=(y0+ans-1)%P2+1;
			x1=(x1+ans-1)%P1+1,y1=(y1+ans-1)%P2+1;
			if(x0>x1) swap(x0,x1),swap(y0,y1);
			if(x0==x1) a[++cnt]=(line){
    
    x0,x0,0,double(y0>y1?y0:y1)};
			else
			{
    
    
				k=(y1-y0)/(double)(x1-x0);
				a[++cnt]=(line){
    
    x0,x1,k,y0-x0*k};
			}
			modify(1,1,P1,cnt);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huangzihaoal/article/details/108421685
今日推荐