【CSP-S 2019爆零模拟】题解

太菜爆零滚粗了

T1:

考试的时候并没有一眼想到线段树分治的暴力
想了想似乎需要在dfsdfs树上乱搞些东西
但不是很明确就去推

结果还真的是
具体的说考虑建出树来
对每个点维护到父亲的边在多少个奇环偶环里
对于一条树边
如果被所有奇环包含而不被偶环包含就可以
如果被偶环包含那么怎么删都不行
对于返祖边
如果是形成了奇环且只有这个奇环就可以了

然后就完了

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
    char ch=gc();
    int res=0,f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cs const
#define bg begin
#define poly vector<int>
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=2000005;
struct edge{
	int u,v,s,d,in;
	edge(){u=v=s=d=in=0;}
}E[N];
int sip[N],db[N],dep[N],tot;
int vis[N];
int n,m;
vector<pii >e[N];
void dfs(int u){
	vis[u]=1;
	for(pii &x:e[u]){
		int v=x.fi;
		if(vis[v])continue;
		dep[v]=dep[u]+1,dfs(v);
		E[x.se].in=1;
	}
}
void dfs2(int u,int fa){
	vis[u]=1;
	for(pii &x:e[u]){
		int v=x.fi;
		if(v==fa||!E[x.se].in)continue;
		dfs2(v,u);
		sip[u]+=sip[v],db[u]+=db[v];
		E[x.se].s=sip[v],E[x.se].d=db[v];
	}
}
vector<int> ans;
int main(){
	n=read(),m=read();
	for(int i=1;i<=m;i++){
		int u=read(),v=read();
		E[i].u=u,E[i].v=v;
		e[u].pb(pii(v,i)),e[v].pb(pii(u,i));
	}
	for(int i=1;i<=n;i++)if(!vis[i])dfs(i);
	for(int i=1;i<=m;i++){
		if(E[i].in)continue;
		int u=E[i].u,v=E[i].v;
		if(dep[u]<dep[v])swap(u,v);
		if((dep[u]-dep[v]+1)&1)E[i].s=1,tot++,sip[u]++,sip[v]--;
		else E[i].d=1,db[u]++,db[v]--;
	}
	if(!tot){
		cout<<m<<'\n';
		for(int i=1;i<=m;i++)cout<<i<<" ";return 0;
	}
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++)if(!vis[i])dfs2(i,0);
	for(int i=1;i<=m;i++){
		if(E[i].in)
			{if(E[i].s==tot&&!E[i].d)ans.pb(i);}
		else if(tot==1&&E[i].s)ans.pb(i);
	}
	cout<<ans.size()<<'\n';
	for(int &x:ans)cout<<x<<" ";
}

T2:

垃圾搬题人
搬个模板原题
给最低的1010分大暴力
不给nlog2nnlog^2n
不给离线
搬题人nmsl

显然的发现实际上就是插入一个新后缀,在线维护后缀数组
支持比较rkrk

但是需要做到O(1)O(1)查询
考场上由于不会后缀平衡树
想的是用setset直接维护,比较也想到了用实数取midmid
但是直接setset并不能保证取midmid的树高
会炸精度
考完就想到可以重构
于是写个替罪羊树就完了

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ob==ib)?EOF:*ib++;
}
inline void readstring(char *s){
	char ch=gc();
	int top=0;
	while(!(('a'<=ch&&ch<='z')||('A'<=ch&&ch<='Z')))ch=gc();
	while((('a'<=ch&&ch<='z')||('A'<=ch&&ch<='Z')))s[++top]=ch,ch=gc();
}
inline int read(){
    char ch=gc();
    int res=0,f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define pic pair<int,char>
#define fi first
#define se second
#define pb push_back
#define cs const
#define ull unsigned long long
#define puu pair<ull,ull>
#define bg begin
#define poly vector<int>
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=1000005;
int pos[N],s[N],n,m,len,rt,pp[N],bel[N<<3];
double val[N];
cs double lim=1e18;
namespace SBT{
	cs double alpha=0.75;
	int tot,lc[N<<3],rc[N<<3],siz[N<<3],stk[N<<3],id[N<<3],top;
	void collect(int u){
		if(!u)return;
		collect(lc[u]),stk[++top]=u,collect(rc[u]);
	}
	int build(int l,int r,double vl,double vr){
		if(l>r)return 0;
		int mid=(l+r)>>1,u=stk[mid];
		double vmid=(vl+vr)/2;
		val[u]=vmid,lc[u]=rc[u]=0;
		lc[u]=build(l,mid-1,vl,vmid),rc[u]=build(mid+1,r,vmid,vr);
		siz[u]=siz[lc[u]]+siz[rc[u]]+1;return u;
	}
	inline int rebuild(int u,double l,double r){
		top=0,collect(u);
		return build(1,top,l,r);
	}
	inline bool comp(int a,int b){
		return s[a]==s[b]?val[bel[a-1]]<=val[bel[b-1]]:s[a]<=s[b];
	}
	void insert(int &u,double l,double r,int p){
		double mid=(l+r)/2;
		if(!u){
			u=++tot,val[u]=mid,siz[u]=1,id[tot]=p,bel[p]=tot;return;
		}
		if(alpha*siz[u]<max(siz[lc[u]],siz[rc[u]]))u=rebuild(u,l,r);
		if(comp(p,id[u]))insert(lc[u],l,mid,p);
		else insert(rc[u],mid+1,r,p);
		siz[u]=siz[lc[u]]+siz[rc[u]]+1;
	}
}
namespace Seg{
	int mn[N<<2];
	#define lc (u<<1)
	#define rc ((u<<1)|1)
	#define mid ((l+r)>>1)
	#define comp(a,b) (val[bel[(a)]]<=val[bel[(b)]])
	inline void pushup(int u){
		mn[u]=comp(pos[mn[lc]],pos[mn[rc]])?mn[lc]:mn[rc];
	}
	void build(int u,int l,int r){
		if(l==r){mn[u]=l;return;}
		build(lc,l,mid),build(rc,mid+1,r);
		pushup(u);
	}
	void update(int u,int l,int r,int p){
		if(l==r)return;
		if(p<=mid)update(lc,l,mid,p);
		else update(rc,mid+1,r,p);
		pushup(u);
	}
	int query(int u,int l,int r,int st,int des){
		if(st<=l&&r<=des)return mn[u];
		if(des<=mid)return query(lc,l,mid,st,des);
		if(mid<st)return query(rc,mid+1,r,st,des);
		int al=query(lc,l,mid,st,des),ar=query(rc,mid+1,r,st,des);
		return comp(pos[al],pos[ar])?al:ar;
	}
}
char ss[N];
int last,tp;
int main(){
	n=read(),m=read(),len=read();
	readstring(ss);
	reverse(ss+1,ss+len+1);
	for(int i=1;i<=len;i++)s[i]=ss[i]-'a'+1,SBT::insert(rt,0,lim,i);
	for(int i=1;i<=n;i++)pos[i]=read();
	Seg::build(1,1,n);
	for(int i=1;i<=m;i++){
		readstring(ss);
		if(ss[1]=='C'){
			int x=read(),p=read();
			pos[x]=p,Seg::update(1,1,n,x);
		}
		else if(ss[1]=='Q'){
			int l=read(),r=read();
			cout<<(last=Seg::query(1,1,n,l,r))<<'\n';
		}
		else{
			int c=(read()^last)+1;
			s[++len]=c,SBT::insert(rt,0,lim,len);
		}
	}
}

T3:

之前雅礼集训考过
虽然也是cfcf原题

显然就是要把最大的子树中选一个适合的接到最小的子树
于是可以线段树合并维护
每次在线段树上找前驱后继就可以做到lognlogn
但是人太蠢写了个二分多一个loglog
还要考虑子树的补集的
其实可以直接在dfsdfs序上建主席树维护
但是人太蠢写了换根的做法
就需要维护子树合并的前后缀
而且这样不能直接维护到根的点
因为往下走会不断修改
所以还需要单独维护一个到根的差分一下

代码又臭又长又垃圾
而且会被菊花图和一个点给叉掉竟然没有被卡
而且细节贼多

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ob==ib)?EOF:*ib++;
}
inline int read(){
    char ch=gc();
    int res=0,f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define pic pair<int,char>
#define fi first
#define se second
#define pb push_back
#define cs const
#define bg begin
#define poly vector<int>
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=100005;
char x;
int rt[N],fg,n;
namespace Seg{
	cs int M=N*200;
	int siz[M],lc[M],rc[M],tot;
	#define mid ((l+r)>>1)
	inline int copy(int u){
		int now=++tot;
		lc[now]=lc[u],rc[now]=rc[u],siz[now]=siz[u];return now;
	}
	inline void insert(int &u,int l,int r,int p){
		u=copy(u),siz[u]++;
		if(l==r)return;
		if(p<=mid)insert(lc[u],l,mid,p);
		else insert(rc[u],mid+1,r,p);
	}
	void merge(int &u,int r1,int r2){
		if(!r1||!r2){u=r1+r2;return;}
		u=++tot,siz[u]=siz[r1]+siz[r2];
		merge(lc[u],lc[r1],lc[r2]);
		merge(rc[u],rc[r1],rc[r2]);
	}
	int query(int u,int l,int r,int st,int des){
		if(!u)return 0;
		//if(fg)cerr<<u<<" "<<l<<" "<<r<<" "<<st<<" "<<des<<'\n';
		if(st>des||st>r||des<l)return 0;
		if(st<=l&&r<=des)return siz[u];
		int res=0;
		if(st<=mid)res+=query(lc[u],l,mid,st,des);
		if(mid<des)res+=query(rc[u],mid+1,r,st,des);
		return res;
	}
	void write(int u,int l,int r){
		if(!u)return;
		if(l==r)cout<<l<<" "<<siz[u]<<'\n';
		write(lc[u],l,mid),write(rc[u],mid+1,r);
	}
	#undef mid
}
vector<int> e[N];
int str,siz[N],fa[N],in[N],ans[N],tort[N];
char y;
void dfs1(int u){
	siz[u]=1;
	for(int i=0;i<e[u].size();i++){
		int v=e[u][i];
		if(v==fa[u])continue;
		dfs1(v),Seg::merge(rt[u],rt[u],rt[v]);
	//	cerr<<u<<" "<<v<<" "<<siz[v]<<'\n';
		siz[u]+=siz[v];
	}
	Seg::insert(rt[u],1,n,siz[u]);
}
void getrt(int u){
	int now=tort[u];
	Seg::insert(now,1,n,siz[u]);
	for(int i=0;i<e[u].size();i++){
		int v=e[u][i];
		if(v==fa[u])continue;
		tort[v]=now,getrt(v);
	}
}
struct node{
	int f,s,t,l;
	node(int _f=0,int _s=0,int _t=0,int _l=0):f(_f),s(_s),t(_t),l(_l){}
	friend inline bool operator <(cs node &a,cs node &b){
		return a.f<b.f;
	}
};
inline int solve(vector<node> now){
	int n=now.size();
	sort(now.bg(),now.end());
	int del=now[n-1].f-now[0].f,pl,pr;
	if(!del)return now[n-1].f;
	if(del&1)pl=del/2,pr=del/2+1;
	else pl=del/2,pr=del/2;
	int l=0,r=::n,res=0;
	while(l<=r){
		int mid=(l+r)>>1;
		if(Seg::query(now[n-1].s,1,::n,pl-mid+1,pr+mid-1)+Seg::query(now[n-1].t,1,::n,pl-mid+1+now[n-1].l,pr+mid-1+now[n-1].l)>0)r=mid-1,res=mid;
		else l=mid+1;
	}
	int ret=max(now[n-1].f-(pl-res+1),now[0].f+(pl-res+1));
	if(n>2)chemx(ret,now[n-2].f);
	return ret;
}
void dfs2(int u,int rtfa){
	if(in[u]==1){ans[u]=n-1;}
	else {
		vector<node> all;
		for(int i=0;i<e[u].size();i++){
			int v=e[u][i];
			if(v==fa[u])continue;
			all.pb(node(siz[v],rt[v],0,0));
		}
		if(fa[u])all.pb(node(n-siz[u],rtfa,tort[u],siz[u]));
		ans[u]=solve(all);
	}
	vector<int> pre,suf;
	for(int i=0;i<e[u].size();i++){
		int v=e[u][i];
		if(v==fa[u])continue;
		int now=rt[v];
		if(i)Seg::merge(now,pre[i-1],now);
		pre.pb(now);
	}
	suf.resize(e[u].size());
	for(int i=(int)e[u].size()-1;i>=0;i--){
		int v=e[u][i];
		if(v==fa[u])continue;
		int now=rt[v];
		if(i+1!=(int)e[u].size())Seg::merge(now,suf[i+1],now);
		suf[i]=now;
	}
	for(int i=0;i<e[u].size();i++){
		int v=e[u][i];
		if(v==fa[u])continue;
		int now=rtfa;
		if(i)Seg::merge(now,now,pre[i-1]);
		if(i+1!=e[u].size())Seg::merge(now,now,suf[i+1]);
		dfs2(v,now);
	}
}
int main(){
	n=read();str=1;
	for(int i=2;i<=n;i++){
		int u=read();
	 e[u].pb(i),fa[i]=u,in[u]++,in[i]++;
	}
	dfs1(str),getrt(str);
	dfs2(str,0);
	for(int i=1;i<=n;i++)cout<<ans[i]<<'\n';
}
posted @ 2019-10-05 16:55  Stargazer_cykoi  阅读(139)  评论(0编辑  收藏  举报