zr2019暑期高端峰会AB组day3

文章目录

  • zr2019暑期高端峰会AB组day3
    • A. 游戏
    • B. 画画
    • C. 交易
          • T1代码
          • T2赛后代码
          • T3赛后代码

zr2019暑期高端峰会AB组day3

A. 游戏

link

这题考场上花了不少时间,虽然想的是小题大做维护环的链表但总归正确性是有的,但是有傻逼错误, O ( 1 ) O(1) O(1)的函数我用 O ( n ) O(n) O(n)实现直接起飞,我拍了几百组1000的数据本以为稳了,下次一定要记得造极限数据测下时间

  • 这题做法八仙过海,其中有一波是注意到了分别维护奇数位置的数和偶数位置的数,每次就是交换这两个数列或者做小小的变动,于是搞个两端延申的队列就行了,这个好妙,没想到
  • 我的做法属于另一波没注意到这个性质的做法,假如一个木棍都不删除,我们可以 O ( 1 ) O(1) O(1)求出第a层第b列的小球编号是多少,那么我们考虑那些被抽掉的木棍,相当于我们交换了应该出现在这两个位置的小球的最终答案,swap就行了,结果我还写了个链表维护断环并环

B. 画画

link

这题的两个小结论

  • 不管怎么走,最后走出来的形状是一样的,这里的形状和题目定义已知
  • 那既然这样,那么理论上方案唯一,但是由于这两条路径会相交,相交的话我们就可以有两种选择,所以假设有 c n t cnt cnt个交点,那么答案就是 2 c n t 2^{cnt} 2cnt

于是我们安排两个人,同时从左上角走到右下角,一个能往右就往右,另一个能往下就往下,如果相交就 c n t + + cnt++ cnt++

于是它就是一个很妙的脑筋急转弯结论题

C. 交易

link

部分分什么的蛇皮做法就不细说了,点分治的正解好像没太搞懂,但是LCT的做法是真的妙

  • 我们关注一条边,当它关上的那一刻之前,两边的联通块的信息必然相容,这很显然,当它再次打开的时候两边的联通块信息在再次互补,但是上次已经交流过的信息不会产生贡献,那我们设两个联通块这是的信息量分别是 v a l 1 , v a l 2 val_1,val_2 val1,val2,这条边上次关闭前它们的共同信息量是 l a s t last last,那么当这条边再次打开的时候,这整个联通块的信息量会变成 v a l 1 + v a l 2 − l a s t val_1+val_2-last val1+val2last
  • 所以我们并不用维护每个点有的信息具体是些什么,只要维护每个联通块掌握的信息量即可
  • 那么我们将这个信息量维护在原树上深度最低的那个点上,然后就可以了

还要感谢pb大佬对我这个菜鸡的帮扶

T1代码
#include
#define FOR(i,a,b) for (register int i=(a);i<=(b);i++)
#define For(i,a,b) for (register int i=(a);i>=(b);i--)
#define mem(i,j) memset(i,j,sizeof(i))
using namespace std;
typedef long long ll;
const int N=2e5+5;
int h,w,n,a[N],b[N],x[N],y[N],tmp[N],ans[N],back[N],mk[N],out[N];
int sb,vis[N];
int v[2005][2005],pos[N];
struct modify
{
	int a,b;
}q[N];
bool cmp(const modify x,const modify y) {return x.a<y.a;}
int read()
{
	int x=0,f=1;
	char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f*x;
}
int Get_num(int col,int round,int pos)
{
	int ret=pos;
	int dir;
	if ((pos%2==0&&round%2==1)||(pos%2==1&&round%2==0)) dir=-1;
	else dir=1;
	round%=col*2;
	while (round>0)
	{
		int del,move;
		if (dir==1) del=col-ret;
		else del=ret-1;
		if (dir==1)
		{
			move=min(round,del);
			ret+=move;
			round-=move;
			round--;
			dir*=-1;
		}
		else 
		{
			move=min(round,del);
			ret-=move;
			round-=move;
			round--;
			dir*=-1;
		}
	}
	return ret;
}
void Debug()
{
	while (1)
	{
		int x=read(),y=read(),z=read();
		printf("%d\n",Get_num(x,y,z));
	}
	return;
}
void Solve()
{
	FOR(i,1,w) ans[i]=i;
	FOR(i,1,n) v[a[i]][b[i]]=1;
	FOR(i,1,h)
	{
		if (i%2==1)
			for (int j=1;j<w;j+=2) if (!v[i][j]) swap(ans[j],ans[j+1]);
		if (i%2==0)
			for (int j=2;j<w;j+=2) if (!v[i][j]) swap(ans[j],ans[j+1]);
	}
	FOR(i,1,w) pos[ans[i]]=i;
	FOR(i,1,w) printf("%d\n",pos[i]);
	return;
}
int main()
{
//	freopen("data.in","r",stdin);
//	freopen("myans.out","w",stdout);
	h=read(),w=read(),n=read();
	FOR(i,1,n) a[i]=read(),b[i]=read(),q[i]=(modify){a[i],b[i]};
	sort(q+1,q+n+1,cmp);
	FOR(i,1,n) x[i]=Get_num(w,q[i].a,q[i].b),y[i]=Get_num(w,q[i].a,q[i].b+1);
	FOR(i,1,w) tmp[i]=Get_num(w,h,i);
	if (n<=2000)
	{
		Solve();
		exit(0);
	}
	FOR(i,1,n)
	{
		if (x[i]==y[i]) continue;
		if ((!back[x[i]])&&(!back[y[i]]))
		{
			mk[x[i]]=y[i];
			mk[y[i]]=x[i];
			back[x[i]]=y[i];
			back[y[i]]=x[i];
		}
		else if (back[x[i]]&&(!back[y[i]]))
		{
			mk[y[i]]=x[i];
			mk[back[x[i]]]=y[i];
			back[y[i]]=back[x[i]];
			back[x[i]]=y[i];
		}
		else if (back[y[i]]&&(!back[x[i]]))
		{
			mk[x[i]]=y[i];
			mk[back[y[i]]]=x[i];
			back[x[i]]=back[y[i]];
			back[y[i]]=x[i];
		}
		else if (back[x[i]]&&back[y[i]])//problem here
		{
			int p1=x[i],p2=y[i];
			if (mk[p1]==p2&&mk[p2]==p1)
			{
				mk[p1]=mk[p2]=0;
				back[p1]=back[p2]=0;
			}
			else if (mk[p1]==p2)
			{
				mk[back[p1]]=p2;
				back[p2]=back[p1];
				mk[p1]=back[p1]=0;
			}
			else if (mk[p2]==p1)
			{
				mk[back[p2]]=p1;
				back[p1]=back[p2];
				mk[p2]=back[p2]=0;
			}
			else
			{
				int t1=back[p2],t2=back[p1];
				mk[t1]=p1;
				back[p1]=t1;
				mk[t2]=p2;
				back[p2]=t2;
			}
		}
	}
	FOR(i,1,w)
		if (back[tmp[i]]) ans[i]=back[tmp[i]];
		else ans[i]=tmp[i];
	FOR(i,1,w) out[ans[i]]=i;
	FOR(i,1,w) vis[out[i]]=1;
	FOR(i,1,w) if (!vis[i]) sb=i;
	FOR(i,1,w) if (!out[i]) out[i]=sb;
	FOR(i,1,w) printf("%d\n",out[i]);
//	Debug();
	return 0;
}
T2赛后代码
#include
#define FOR(i,a,b) for (register int i=(a);i<=(b);i++)
using namespace std;
const int N=1e6+5;
const int mod=1e9+7;
int T,n,a[N],b[N],a1,a2,b1,b2,tag,cnt,same;
int read()
{
	int x=0,f=1;
	char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f*x;
}
int qpow(int x,int y)
{
	int ret=1;
	while (y)
	{
		if (y&1) ret=1LL*ret*x%mod;
		y>>=1;
		x=1LL*x*x%mod;
	}
	return ret;
}
int main()
{
	T=read();
	while (T--)
	{
		tag=1,cnt=0,same=1;
		n=read();
		FOR(i,1,n) a[i]=read();
		FOR(i,1,n) b[i]=read();
		a1=b1=a2=b2=1;
		a[1]--;
		b[1]--;
		FOR(i,1,n*2-2)
		{
			if (a[a1]&&b1<n) b1++;
			else a1++;
			if (b[b2]&&a2<n) a2++;
			else b2++;
			a[a1]--,b[b2]--;
			if (a1!=a2||b1!=b2) a[a2]--,b[b1]--,same=0;
			else if (!same) cnt++,same=1;
		}
		FOR(i,1,n) if (a[i]||b[i]) tag=0;
		if (!tag) printf("0\n");
		else printf("%d\n",qpow(2,cnt));
	}
	return 0;
}
T3赛后代码
#include
#define FOR(i,a,b) for (register int i=(a);i<=(b);i++)
using namespace std;
const int N=2e5+5;
int n,m,q,u[N],v[N];
int pre[N],ch[N][2],rev[N];
int query[N],ans[N],val[N],opt[N],now[N],last[N];
//把联通块的信息维护在了原树深度最浅的点的val上 
//所以所有破坏树结构的操作(带makeroot) 都要重新调整val的位置 
//当然pb大佬教我的不破坏树结构的方法踩了我一百毫秒 
int read()
{
	int x=0,f=1;
	char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f*x;
}

int nroot(int x) {return ch[pre[x]][0]==x||ch[pre[x]][1]==x;}
void Update_rev(int p) {if (!p) return;swap(ch[p][0],ch[p][1]);rev[p]^=1;return;}
void Push(int p) {if (!rev[p]) return;if (!rev[p]) return;Update_rev(ch[p][0]);Update_rev(ch[p][1]);rev[p]=0;return;}
void Rotate(int x)
{
	int y=pre[x],k=(ch[y][0]==x);
	ch[y][!k]=ch[x][k];
	if (ch[x][k]) pre[ch[x][k]]=y;
	if (pre[y]&&nroot(y)) ch[pre[y]][(ch[pre[y]][1]==y)]=x;
	pre[x]=pre[y];
	pre[y]=x;
	ch[x][k]=y;
	return;
}
void Pushall(int x)
{
	if (nroot(x)) Pushall(pre[x]);
	Push(x);
	return;
}
void Splay(int x)
{
	Pushall(x);
	while (nroot(x))
	{
		int y=pre[x],z=pre[y];
		if (nroot(y))
		{
			if ((ch[z][1]==y)xor(ch[y][1]==x)) Rotate(x);
			else Rotate(y);
		}
		Rotate(x);
	}
	return;
}
void Access(int x)
{
	int y=0;
	for (;x;x=pre[y=x])
	{
		Splay(x);
		ch[x][1]=y;
	}
	return;
}
int Getrt(int x)
{
	Access(x);
	Splay(x);
	while (ch[x][0]) x=ch[x][0];
	Splay(x);
	return x;
}
void Make_root(int x)
{
	int tmpval=val[Getrt(x)];
	Access(x);
	Splay(x);
	Update_rev(x);
	val[x]=tmpval;
	return;
}
void Link(int u,int v)
{
	Make_root(u);
	pre[u]=v;
	return;
}
void Cut(int u,int v)
{
	int tmpval=val[Getrt(u)];
	Make_root(u);
	Access(v);
	Splay(v);
	pre[u]=ch[v][0]=0;
	val[Getrt(u)]=val[Getrt(v)]=tmpval;
	return;
}
int main()
{
	n=read(),m=read(),q=read();
	FOR(i,1,n-1) u[i]=read(),v[i]=read();
	FOR(i,1,m) opt[i]=read();
	FOR(i,1,q) query[i]=read();
	FOR(i,1,n) val[i]=1;
	FOR(i,1,m)
	{
		if (!now[opt[i]])
		{
			int v1=val[Getrt(u[opt[i]])],v2=val[Getrt(v[opt[i]])];
			Link(u[opt[i]],v[opt[i]]);
			val[Getrt(u[opt[i]])]=v1+v2-last[opt[i]];
		}
		else
		{
			last[opt[i]]=val[Getrt(u[opt[i]])];
			Cut(u[opt[i]],v[opt[i]]);
		}
		now[opt[i]]^=1;
	}
	FOR(i,1,q) ans[i]=val[Getrt(query[i])];
	FOR(i,1,q) printf("%d\n",ans[i]);
	return 0;
}

你可能感兴趣的:(比赛总结,正睿集训)