雅礼集训2017day7乱写

看来\(3\)的倍数的天数都没有

t1

水了一发\(SA\),然后\(WA\)

冷静分析发现我是\(sb\)

先搞一个\(SAM\),位置的前缀长度就是那些位置代表节点的\(len[lca]\)

我们先把询问离线,按\(r\)排序,然后扫描数组

我们发现这个事情其实和树点涂色每次把一条链染上同一种颜色

如果在\(access\)过程中某个点已经被染色了,那么说明这个点是某两个位置的\(lca\),用线段树来维护最大值

注意保存两个位置时保存在左侧节点

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
	inline int read()
	{
		int x=0;char ch,f=1;
		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
		if(ch=='-') f=0,ch=getchar();
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
		return f?x:-x;
	}
	const int N=4e5+10,p=1e9+7;
	int n,m,tot=1,pre=1;
	char s[N];
	int pos[N],ret[N];
	struct node
	{
		int l,r,id;
		inline bool operator < (const node &t) const
		{
			return r<t.r;
		}
	}q[N];
	struct SAM
	{
		int fa[N],len[N],endpos[N],son[N][2];
		inline void insert(int c)
		{
			int p=pre,np=pre=++tot;endpos[tot]=1;
			len[np]=len[p]+1;
			for(;p&&!son[p][c];p=fa[p]) son[p][c]=np;
			if(!p) fa[np]=1;
			else
			{
				int q=son[p][c];
				if(len[q]==len[p]+1) fa[np]=q;
				else
				{
					int nq=++tot;
					for(int i=0;i<2;++i) son[nq][i]=son[q][i];
					len[nq]=len[p]+1;
					fa[nq]=fa[q];
					fa[q]=fa[np]=nq;
					for(;p&&son[p][c]==q;p=fa[p]) son[p][c]=nq;
				}
			}
		}
	}sam;
	struct SGT
	{
		int ans[N<<2];
		inline void update(int pos,int l,int r,int p,int k)
		{
		//	cout<<pos<<' '<<l<<' '<<r<<endl;
			ans[p]=max(ans[p],k);
			if(l==r) return;
			if(pos<=mid) update(pos,l,mid,ls(p),k);
			else update(pos,mid+1,r,rs(p),k);
		}
		inline int query(int tl,int tr,int l,int r,int p)
		{
			if(tl<=l&&r<=tr) return ans[p];
			int ret=0;
			if(tl<=mid) ret=query(tl,tr,l,mid,ls(p));
			if(tr>mid) ret=max(ret,query(tl,tr,mid+1,r,rs(p)));
			return ret;
		}
	}tr;
	struct LCT	
	{
		int st[N],f[N],cor[N],son[N][2];
		inline void pushdown(int x)
		{
			if(son[x][0]) cor[son[x][0]]=cor[x];
			if(son[x][1]) cor[son[x][1]]=cor[x];
		}
		inline bool nroot(int x)
		{
			return son[f[x]][0]==x||son[f[x]][1]==x;
		}
		inline int ident(int x)
		{
			return son[f[x]][1]==x;
		}
		inline void rotate(int x)
		{
			int y=f[x],z=f[y],k=son[y][1]==x,w=son[x][!k];
			if(nroot(y)) son[z][son[z][1]==y]=x;son[x][!k]=y,son[y][k]=w;
			if(w) f[w]=y;f[y]=x,f[x]=z;
		}
		inline void splay(int x)
		{
			int y=x,z=0;
			st[++z]=y;
			while(nroot(y)) st[++z]=y=f[y];
			while(z) pushdown(st[z--]);
			while(nroot(x))
			{
				y=f[x];
				if(nroot(y)) rotate(ident(x)==ident(y)?y:x);
				rotate(x);
			}
		}
		inline void access(int x,int c)
		{
			for(int y=0;x;x=f[y=x])
			{
				splay(x);
				if(cor[x]) tr.update(cor[x],1,n,1,sam.len[x]);
				cor[x]=c;
				son[x][1]=y;
			}
		}
	}lct;
	inline void main()
	{
		n=read(),m=read();
		scanf("%s",s+1);
		for(int i=1;i<=n;++i) sam.insert(s[i]-'0'),pos[i]=pre;
		for(int i=tot;i;--i) lct.f[i]=sam.fa[i];
		for(int i=1;i<=m;++i) q[i].l=read(),q[i].r=read(),q[i].id=i;
		sort(q+1,q+m+1);
		for(int i=1,j=1;i<=n&&j<=m;++i)
		{
			lct.access(pos[i],i);
			for(;j<=m&&q[j].r<=i;++j) ret[q[j].id]=tr.query(q[j].l,i,1,n,1);
		}
		for(int i=1;i<=m;++i) printf("%d\n",ret[i]);
	}
}
signed main()
{
	red::main();
	return 0;
}

t2

重心定义没有一个子树大小乘以二超过\(n\)

我们发现每个节点至多有一颗子树大小超过要求,而且重心在这颗子树内

很多细节。。。很难写(呜呜呜)

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
	inline int read()
	{
		int x=0;char ch,f=1;
		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
		if(ch=='-') f=0,ch=getchar();
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
		return f?x:-x;
	}
	const int N=1e6+10,p=1e9+7;
	int n,sum,num;
	vector<int> eg[N];
	inline void link(int x,int y)
	{
		eg[x].push_back(y);
		eg[y].push_back(x);
	}
	int str[N],mx[N],ans[N],rt;
	inline bool cmp(int x,int y){return str[x]>str[y];}
	inline void find(int now,int fa)
	{
		str[now]=1;
		for(auto t:eg[now])
		{
			if(t==fa) continue;
			find(t,now);
			mx[now]=max(mx[now],str[t]);
			str[now]+=str[t];
		}
		mx[now]=max(mx[now],n-str[now]);
		if(mx[now]<mx[rt]) rt=now;
	}
	inline void dfs(int now,int fa)
	{
		str[now]=1;
		for(auto t:eg[now])
		{
			if(t==fa) continue;
			dfs(t,now);
			str[now]+=str[t];
		}
	}
	inline void dfs2(int now,int fa,int top)
	{
		ans[now]=num+((n-top-str[now])*2>n);
		for(auto t:eg[now]) 
			if(t!=fa) dfs2(t,now,top);
	}
	inline void main()
	{
		n=read();
		for(int x,y,i=1;i<n;++i)
		{
			x=read(),y=read();
			link(x,y);
		}
		mx[0]=p;find(1,0);
		dfs(rt,0);
		sort(eg[rt].begin(),eg[rt].end(),cmp);
		for(auto t:eg[rt])
		{
			sum+=str[t];
			if(sum*2>=n) break;
			++num;
		}
		for(auto t:eg[rt])
		{
			dfs2(t,rt,sum-max(str[t],str[eg[rt][num]]));
		}
		for(int i=1;i<=n;++i) printf("%d\n",ans[i]);
	}
}
signed main()
{
	red::main();
	return 0;
}

我们可以爆搜,复杂度\(O(2^{100})\)

我们发现一条边两个端点一定是一个左括号一个右括号,保证有解的话那么必定有偶环,复杂度上界变为

\(O(2^{50})\)

我们发现如果是只有\(2\)个点环,那么一定是靠左的那个是左括号,可以\(O(1)\)

最坏情况变成了\(4\)个点的环,最多有\(25\)个,复杂度\(O(2^25)\)

好像可做了,爆搜吧qwq

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
	inline int read()
	{
		int x=0;char ch,f=1;
		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
		if(ch=='-') f=0,ch=getchar();
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
		return f?x:-x;
	}
	const int N=210,p=1e9+7;
	int n;
	vector<int> eg[N];
	bool vis[N];
	int cir[N],tot;
	int c[N][N],b[N];
	int ans[N];
	int len[N],num;
	inline void link(int x,int y)
	{
		eg[x].push_back(y);
		eg[y].push_back(x);
	}
	inline void sea(int now,int fa)
	{
		if(vis[now]) return;
		vis[now]=1;
		cir[tot++]=now;
		for(auto t:eg[now])
			if(t!=fa) sea(t,now);
	}
	inline void search(int now)
	{
		tot=0;
		sea(now,0);
		if(tot==2) ans[min(cir[0],cir[1])]=1,ans[max(cir[0],cir[1])]=-1;
		else
		{
			len[++num]=tot;
			for(int i=0;i<tot;++i)
				c[num][i]=cir[i],b[cir[i]]=num;
		}
	}
	bool flag;
	inline void dfs(int now,int sum)
	{
		if(sum<0) return;
		if(now==n+1)
		{
			for(int i=1;i<=n;++i)
				putchar(ans[i]==1?'(':')');
			flag=1;return;
		}
		if(!ans[now])
		{
			ans[c[b[now]][0]]=1;
			for(int i=1;i<=len[b[now]];++i)
				ans[c[b[now]][i]]=-ans[c[b[now]][i-1]];
			dfs(now+1,sum+ans[now]);
			if(flag) return;
			
			for(int i=0;i<len[b[now]];i++) ans[c[b[now]][i]]=-ans[c[b[now]][i]];
			dfs(now+1,sum+ans[now]);
			if(flag) return;
			
			for(int i=0;i<len[b[now]];++i) ans[c[b[now]][i]]=0;
		}
		else dfs(now+1,sum+ans[now]);
	}
	inline void main()
	{
		n=read();
		for(int i=1;i<=n;++i) link(read(),i);
		for(int i=1;i<=n;++i)
			if(!vis[i]) search(i);
		dfs(1,0);
	}
}
signed main()
{
	red::main();
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/knife-rose/p/12771244.html