zoukankan      html  css  js  c++  java
  • 【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<<'
    ';
    		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()<<'
    ';
    	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))<<'
    ';
    		}
    		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<<'
    ';
    		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]<<'
    ';
    		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]<<'
    ';
    		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]<<'
    ';
    }
    
  • 相关阅读:
    安装k8s和NVIDIA环境
    docker使用阿里云加速器
    Ubuntu16安装NVIDIA驱动后重复登录 简单粗暴
    Ubuntu TTY 字体大小 目录颜色 中文乱码 设置
    vim使用记录
    k8s内运行ubuntu容器
    IRelationalOperator接口
    IArea接口(计算多边形面积)
    ITopologicalOperator接口
    通过ArcEngine接口建立凸包(一)
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328409.html
Copyright © 2011-2022 走看看