zoukankan      html  css  js  c++  java
  • 省选测试25

    A. two

    分析

    考虑当前要删红边,删蓝边类似

    从根节点 (1) 开始 (dfs) 遍历整棵蓝树

    定义 (dfn1[i],dfn2[i)] 分别为 (dfs) 中进入节点 (i) 子树的时刻和 (dfs) 中离开节点 (i) 子树的时刻

    对于红树中的第 (i) 条边 (x[i],y[i])

    定义 (u[i]=min(dfn1[x[i]],dfn1[y[i]]),v[i]=max(dfn1[x[i]],dfn1[y[i]]))

    接下来考虑删除蓝树中的一条边 ((p, q)),这里令 (p)(q) 的父亲

    那么 ((p,q)), 对应的红树中的坏边,即为满足 (u[i],v[i]) 中有且仅有一个数落在区间 ([dfn1[q],dfn2[q]])

    可以分成两种情况

    (1)(dfn1[q] leq u[i] leq dfn2[q],v[i]>dfn2[q])

    (2)、$dfn1[q] leq v[i] leq dfn2[q],u[i]<dfn1[q] $

    那么就可以开两颗线段树,线段树的每一个节点维护一个(vector)

    第一颗以 (u[i]) 作为下标,按照 (v[i]) 从小到大排序

    第二颗以 (v[i]) 作为下标,按照 (u[i]) 从大到小排序

    查询的时候直接在线段树的节点对应的 (vector) 上不断 (popback) 即可

    因为每一条边只会存到 (log)(vector) 里,删过一次就不会恢复

    所以复杂度是 (nlogn) ,常数较大

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #define rg register
    inline int read(){
        rg int x=0,fh=1;
        rg char ch=getchar();
        while(ch<'0' || ch>'9'){
            if(ch=='-') fh=-1;
            ch=getchar();
        }
        while(ch>='0' && ch<='9'){
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*fh;
    }
    const int maxn=2e5+5;
    int n;
    struct Graph{
    	int h[maxn],tot;
    	struct asd{
    		int to,nxt;
    	}b[maxn<<1];
    	void ad(rg int aa,rg int bb){
    		b[tot].to=bb;
    		b[tot].nxt=h[aa];
    		h[aa]=tot++;
    	}
    	int dfn1[maxn],dfn2[maxn],siz[maxn],dfnc,x[maxn],y[maxn],jud[maxn],valu[maxn],valv[maxn];
    	void dfs(rg int now,rg int lat){
    		siz[now]=1;
    		dfn1[now]=++dfnc;
    		for(rg int i=h[now];i!=-1;i=b[i].nxt){
    			rg int u=b[i].to;
    			if(u==lat) continue;
    			dfs(u,now);
    			siz[now]+=siz[u];
    		}
    	}
    	void build(){
    		tot=1;
    		memset(h,-1,sizeof(h));
    		rg int aa;
    		for(rg int i=2;i<=n;i++){
    			aa=read();
    			x[i-1]=i,y[i-1]=aa;
    			ad(aa,i),ad(i,aa);
    		}
    		dfs(1,0);
    		for(rg int i=1;i<=n;i++) dfn2[i]=dfn1[i]+siz[i]-1;
    	}
    }gra[2];
    int sta[maxn],tp,sta2[maxn],tp2;
    struct jie{
    	int val,id;
    	jie(){}
    	jie(rg int aa,rg int bb){
    		val=aa,id=bb;
    	}
    };
    bool cmp1(rg jie aa,rg jie bb){
    	return aa.val<bb.val;
    }
    bool cmp2(rg jie aa,rg jie bb){
    	return aa.val>bb.val;
    }
    struct Tree{
    	std::vector<jie> gup[maxn<<2],gdow[maxn<<2];
    	void ad(rg int da,rg int nl,rg int nr,rg int wz,rg int val,rg int id,rg int op){
    		if(op==0) gup[da].push_back(jie(val,id));
    		else gdow[da].push_back(jie(val,id));
    		if(nl==nr) return;
    		rg int mids=(nl+nr)>>1;
    		if(wz<=mids) ad(da<<1,nl,mids,wz,val,id,op);
    		else ad(da<<1|1,mids+1,nr,wz,val,id,op);
    	}
    	void dfs(rg int da,rg int nl,rg int nr){
    		std::sort(gup[da].begin(),gup[da].end(),cmp1);
    		std::sort(gdow[da].begin(),gdow[da].end(),cmp2);
    		if(nl==nr) return;
    		rg int mids=(nl+nr)>>1;
    		dfs(da<<1,nl,mids),dfs(da<<1|1,mids+1,nr);
    	}
    	void cx(rg int da,rg int nl,rg int nr,rg int l,rg int r,rg int val,rg int op,rg int col){
    		if(nl>=l && nr<=r){
    			if(op==0){
    				rg int tmp=gup[da].size();
    				while(tmp && gup[da][tmp-1].val>val){
    					if(!gra[col].jud[gup[da][tmp-1].id]) sta[++tp]=gup[da][tmp-1].id;
    					gra[col].jud[gup[da][tmp-1].id]=1;
    					tmp--,gup[da].pop_back();
    				}
    			} else {
    				rg int tmp=gdow[da].size();
    				while(tmp && gdow[da][tmp-1].val<val){
    					if(!gra[col].jud[gdow[da][tmp-1].id]) sta[++tp]=gdow[da][tmp-1].id;
    					gra[col].jud[gdow[da][tmp-1].id]=1;
    					tmp--,gdow[da].pop_back();
    				}
    			}
    			return;
    		}
    		rg int mids=(nl+nr)>>1;
    		if(l<=mids) cx(da<<1,nl,mids,l,r,val,op,col);
    		if(r>mids) cx(da<<1|1,mids+1,nr,l,r,val,op,col);
    	}
    }tre[2];
    int main(){
    	n=read();
    	gra[0].build(),gra[1].build();
    	sta[tp=1]=read();
    	for(rg int o=0;o<=1;o++){
    		for(rg int i=1;i<n;i++){
    			gra[o].valu[i]=std::min(gra[o].dfn1[gra[o^1].x[i]],gra[o].dfn1[gra[o^1].y[i]]);
    			gra[o].valv[i]=std::max(gra[o].dfn1[gra[o^1].x[i]],gra[o].dfn1[gra[o^1].y[i]]);
    		}
    	}
    	for(rg int o=0;o<=1;o++){
    		for(rg int i=1;i<n;i++){	
    			if(o==1 && i==sta[1]) continue;
    			tre[o].ad(1,1,n,gra[o].valu[i],gra[o].valv[i],i,0);
    			tre[o].ad(1,1,n,gra[o].valv[i],gra[o].valu[i],i,1);
    		}
    	}
    	tre[0].dfs(1,1,n),tre[1].dfs(1,1,n);
    	rg int aa,bb,now=0;
    	printf("Blue
    %d
    ",sta[1]);
    	gra[0].jud[sta[1]]=1;
    	while(1){
    		now^=1;
    		for(rg int i=1;i<=tp;i++) sta2[i]=sta[i];
    		tp2=tp,tp=0;
    		for(rg int i=1;i<=tp2;i++){
    			aa=gra[now^1].x[sta2[i]],bb=gra[now^1].y[sta2[i]];
    			if(gra[now^1].dfn1[aa]>gra[now^1].dfn1[bb]) std::swap(aa,bb);
    			tre[now^1].cx(1,1,n,gra[now^1].dfn1[bb],gra[now^1].dfn2[bb],gra[now^1].dfn2[bb],0,now);
    			tre[now^1].cx(1,1,n,gra[now^1].dfn1[bb],gra[now^1].dfn2[bb],gra[now^1].dfn1[bb],1,now);
    		}
    		if(!tp) break;
    		std::sort(sta+1,sta+1+tp);
    		if(now==1) printf("Red
    ");
    		else printf("Blue
    ");
    		for(rg int i=1;i<=tp;i++) printf("%d ",sta[i]);
    		printf("
    ");
    	}
    	return 0;
    }
    

    B. bracket

    分析

    对这棵树进行点分治,求出重心到每个点的前缀和 (s)

    对于两个点 (i, j) ,假设是从 (i) 开始走到 (j)

    如果它们的 (s) 互为相反数

    且它们的 (s) 都是重心到它们的路径上前缀和的最大/最小值

    那么就是一个合法的括号序列,划分段数就是最值出现的次数

    可以理解为合法括号左边的一段必须满足前缀非负,右边的一段必须满足前缀非正

    反过来之后就是前缀和的最大最小值

    对于重心进行一遍 (dfs) 就可以得到的划分段数以及前缀和

    对于前缀和互为相反数的括号序列

    按照正负分别存储到两个数组,以划分段数为下标进行卷积就能得到结果

    如果两个括号序列的划分段数都为 (0),那么下标就不减一,否则拼合后还会少一段,下标要减一

    需要注意的是重心的贡献只能算一次,所以 (dfs) 的时候记录两个 (sum)

    一个代表不选重心的,一个代表选重心的

    而且为了防止重复,需要强行规定选重心的只能是前缀,不选重心的只能是后缀

    还要注意的是在进行某个节点整体的更新时,有可能进入不到叶子节点中,此时如果不提前把最大值设为 (1),会出现有的 (vector) 没清空的情况

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cstdlib>
    #include<algorithm>
    #include<ctime>
    #include<vector>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=3e5+5,mod=998244353,G=3;
    int w[25][maxn],wz[maxn];
    inline int addmod(rg int now1,rg int now2){
    	return now1+=now2,now1>=mod?now1-mod:now1;
    }
    inline int delmod(rg int now1,rg int now2){
    	return now1-=now2,now1<0?now1+mod:now1;
    }
    inline int mulmod(rg long long now1,rg int now2){
    	return now1*=now2,now1>=mod?now1%mod:now1;
    }
    inline int ksm(rg int ds,rg int zs){
    	rg int nans=1;
    	while(zs){
    		if(zs&1) nans=mulmod(nans,ds);
    		ds=mulmod(ds,ds);
    		zs>>=1;
    	}
    	return nans;
    }
    void ntt(rg int A[],rg int lim,rg int typ){
    	for(rg int i=0;i<lim;i++) if(i<wz[i]) std::swap(A[i],A[wz[i]]);
    	for(rg int len=1,t0=0;len<lim;len<<=1,t0++){
    		for(rg int j=0,now=len<<1;j<lim;j+=now){
    			for(rg int k=0;k<len;k++){
    				rg int x=A[j+k],y=mulmod(A[j+k+len],w[t0][k]);
    				A[j+k]=addmod(x,y),A[j+k+len]=delmod(x,y);
    			}
    		}
    	}
    	if(typ==-1){
    		rg int ny=ksm(lim,mod-2);
    		std::reverse(A+1,A+lim);
    		for(rg int i=0;i<lim;i++) A[i]=mulmod(A[i],ny);
    	}
    }
    void pre(rg int mmax){
    	for(rg int len=1,t0=0;len<mmax;len<<=1,t0++){
    		w[t0][0]=1,w[t0][1]=ksm(G,(mod-1)/(len<<1));
    		for(rg int j=1;j<len;j++) w[t0][j]=mulmod(w[t0][j-1],w[t0][1]);
    	}
    }
    int h[maxn],tot=1;
    long long ans[maxn];
    struct asd{
    	int to,nxt;
    }b[maxn];
    void ad(rg int aa,rg int bb){
    	b[tot].to=bb;
    	b[tot].nxt=h[aa];
    	h[aa]=tot++;
    }
    int a[maxn],n,m,rt,maxsiz[maxn],siz[maxn],totsiz;
    bool vis[maxn];
    void getroot(rg int now,rg int lat){
    	siz[now]=1,maxsiz[now]=0;
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(u==lat || vis[u]) continue;
    		getroot(u,now);
    		siz[now]+=siz[u];
    		maxsiz[now]=std::max(maxsiz[now],siz[u]);
    	}
    	maxsiz[now]=std::max(maxsiz[now],totsiz-siz[now]);
    	if(maxsiz[now]<maxsiz[rt]) rt=now;
    }
    void getsiz(rg int now,rg int lat){
    	siz[now]=1;
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(u==lat || vis[u]) continue;
    		getsiz(u,now);
    		siz[now]+=siz[u];
    	}
    }
    std::vector<int> wz1[maxn],wz2[maxn];
    int mx,mn,cnt1[maxn],cnt2[maxn],f[maxn];
    void dfs(rg int now,rg int lat,rg int summax,rg int summin,rg int mmax,rg int mmin,rg int cntmax,rg int cntmin){
    	summax+=a[now],summin+=a[now];
    	if(summax>mmax) mmax=summax,cntmax=0;
    	if(summax==mmax) cntmax++,wz1[mmax].push_back(cntmax);
    	if(summin<mmin) mmin=summin,cntmin=0;
    	if(summin==mmin) cntmin++,wz2[-mmin].push_back(cntmin);
    	mn=std::min(mn,mmin),mx=std::max(mx,mmax);
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(u==lat || vis[u]) continue;
    		dfs(u,now,summax,summin,mmax,mmin,cntmax,cntmin);
    	}
    }
    void js(rg int op){
    	for(rg int now=0;now<=mx && -now>=mn;now++){
    		rg int maxdep=0;
    		for(rg int i=0;i<wz1[now].size();i++){
    			rg int tmp=wz1[now][i];
    			maxdep=std::max(maxdep,tmp);
    			cnt1[tmp]++;
    		}
    		for(rg int i=0;i<wz2[now].size();i++){
    			rg int tmp=wz2[now][i];
    			maxdep=std::max(maxdep,tmp);
    			cnt2[tmp]++;
    		}
    		rg int lim=1,bit=0;
    		for(;lim<=maxdep+maxdep;lim<<=1) bit++;
    		for(rg int i=0;i<lim;i++) wz[i]=(wz[i>>1]>>1)|((i&1)<<(bit-1));
    		ntt(cnt1,lim,1),ntt(cnt2,lim,1);
    		for(rg int i=0;i<lim;i++) f[i]=mulmod(cnt1[i],cnt2[i]);
    		ntt(f,lim,-1);
    		if(now==0) for(rg int i=0;i<lim;i++) ans[i]+=f[i]*op;
    		else for(rg int i=1;i<=lim;i++) ans[i-1]+=f[i]*op;
    		for(rg int i=0;i<lim;i++) f[i]=cnt1[i]=cnt2[i]=0;
    	}
    	for(rg int i=0;i<=mx;i++) wz1[i].clear();
    	for(rg int i=0;-i>=mn;i++) wz2[i].clear();
    }
    void solve(rg int now){
    	vis[now]=1;
    	getsiz(now,0);
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(vis[u]) continue;
    		mx=mn=0;
    		dfs(u,0,a[now],0,a[now]>0,0,a[now]>0,0);
    		js(-1);
    	}
    	if(a[now]>0) wz1[1].push_back(1);
    	mx=a[now]>0,mn=0;
    	cnt2[0]++;
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(vis[u]) continue;
    		dfs(u,0,a[now],0,a[now]>0,0,a[now]>0,0);
    	}
    	js(1);
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(vis[u]) continue;
    		rt=0,totsiz=siz[u];
    		getroot(u,0);
    		solve(rt);
    	}
    }
    int main(){
    	memset(h,-1,sizeof(h));
    	n=read();
    	rg int lim=1;
    	for(;lim<=n+n;lim<<=1);
    	pre(lim);
    	rg int aa,bb;
    	for(rg int i=1;i<n;i++){
    		aa=read(),bb=read();
    		ad(aa,bb),ad(bb,aa);
    	}
    	rg char ch;
    	for(rg int i=1;i<=n;i++){
    		scanf(" %c",&ch);
    		if(ch=='(') a[i]=1;
    		else a[i]=-1;
    	}
    	maxsiz[0]=0x3f3f3f3f,totsiz=n,rt=0;
    	getroot(1,0);
    	solve(rt);
    	m=read();
    	for(rg int i=1;i<=m;i++){
    		aa=read();
    		printf("%lld
    ",ans[aa]);
    	}
    	return 0;
    }
    

    C. sum

    分析

    结论题

    (1)、最优集合里每个数最多只有两个不同的质因子

    (2)、若一个数含有两个不同质因子,则一定满足一个 (< sqrt{n}),一个 (>sqrt{n})

    所以可以建出二分图跑一个最大费用可行流

    答案就是一开始的答案加上跑出的费用

    不能跑最大费用最大流,因为有可能为了增广流量而去走费用为负的边

    区别就是前者在最长路小于 (0) 的时候直接退出就行了

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=1e6+5;
    int n,ans,pri[maxn],mmax[maxn],s,t,cnt;
    bool not_pri[maxn];
    void xxs(){
    	not_pri[0]=not_pri[1]=1;
    	for(rg int i=2;i<=n;i++){
    		if(!not_pri[i]) pri[++pri[0]]=i;
    		for(rg int j=1;j<=pri[0] && i*pri[j]<=n;j++){
    			not_pri[i*pri[j]]=1;
    			if(i%pri[j]==0) break;
    		}
    	}
    }
    std::queue<int> q;
    int dis[maxn],incf[maxn],pre[maxn],h[maxn],tot=2;
    bool inq[maxn];
    struct asd{
    	int to,nxt,val,cost;
    }b[maxn<<1];
    void ad(rg int aa,rg int bb,rg int cc,rg int dd){
    	b[tot].to=bb;
    	b[tot].val=cc;
    	b[tot].cost=dd;
    	b[tot].nxt=h[aa];
    	h[aa]=tot++;
    }
    bool spfa(){
    	for(rg int i=1;i<=cnt;i++) dis[i]=-0x3f3f3f3f,incf[i]=0;
    	dis[s]=0,inq[s]=1,q.push(s),incf[s]=0x3f3f3f3f;
    	while(!q.empty()){
    		rg int now=q.front();
    		q.pop();
    		inq[now]=0;
    		for(rg int i=h[now];i!=-1;i=b[i].nxt){
    			rg int u=b[i].to;
    			if(b[i].val && dis[u]<dis[now]+b[i].cost){
    				dis[u]=dis[now]+b[i].cost;
    				pre[u]=i;
    				incf[u]=std::min(incf[now],b[i].val);
    				if(!inq[u]){
    					inq[u]=1;
    					q.push(u);
    				}
    			}
    		}
    	}
    	return dis[t]!=-0x3f3f3f3f;
    }
    int ans2=0;
    void updat(){
    	if(dis[t]<0){
    		printf("%d
    ",ans+1);
    		std::exit(0);
    	}
    	ans+=dis[t]*incf[t];
    	rg int i,now=t;
    	while(now){
    		i=pre[now];
    		b[i].val-=incf[t];
    		b[i^1].val+=incf[t];
    		now=b[i^1].to;
    	}
    }
    int prinum,tax[maxn],rk[maxn];
    void solve(rg int val){
    	prinum=0;
    	rg int tmp=val;
    	for(rg int i=2;i*i<=val;i++){
    		if(val%i==0){
    			tax[++prinum]=i;
    			while(val%i==0) val/=i;
    		}
    	}
    	if(val>1) tax[++prinum]=val;
    	if(prinum!=2) return;
    	if(tax[1]>tax[2]) std::swap(tax[1],tax[2]);
    	if(1LL*tax[1]*tax[1]>=n || 1LL*tax[2]*tax[2]<=n) return;
    	rg int tmpans=0;
    	for(rg int i=1;i<=prinum;i++){
    		if(tmp*tax[i]<=n) return;
    		tmpans+=mmax[tax[i]];
    	}
    	if(tmpans<tmp){
    		ad(rk[tax[1]],rk[tax[2]],1,tmp-tmpans),ad(rk[tax[2]],rk[tax[1]],0,tmpans-tmp);
    	}
    }
    int main(){
    	memset(h,-1,sizeof(h));
    	n=read();
    	xxs();
    	for(rg int i=1;i<=pri[0];i++){
    		rg int now=pri[i];
    		while(1LL*now*pri[i]<=n) now*=pri[i];
    		mmax[pri[i]]=now;
    		ans+=now;
    	}
    	s=1,t=2,cnt=2;
    	for(rg int i=1;i<=pri[0];i++){
    		if(1LL*pri[i]*pri[i]<n){
    			if(!rk[pri[i]]) rk[pri[i]]=++cnt;
    			ad(s,rk[pri[i]],1,0),ad(rk[pri[i]],s,0,0);
    		} else if(1LL*pri[i]*pri[i]>n){
    			if(!rk[pri[i]]) rk[pri[i]]=++cnt;
    			ad(rk[pri[i]],t,1,0),ad(t,rk[pri[i]],0,0);
    		}
    	}
    	for(rg int i=2;i<=n;i++) solve(i);
    	while(spfa()) updat();
    	printf("%d
    ",ans+1);
    	return 0;
    }
    
  • 相关阅读:
    sublime & atom 插件
    正则表达式必知必会读书笔记
    前端自动化工具
    CSS3效果收集
    JS 常用功能收集
    【1】Hover 效果收集
    javascript进阶高手必备知识
    ionic 实现仿苹果手机通讯录搜索功能
    ionic2APP 如何处理返回键问题
    三张图搞懂JavaScript的原型对象与原型链
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/14426875.html
Copyright © 2011-2022 走看看