【考试总结2021-02-20】完整

two

每个阶段删掉 (Red/Blue) 一定是交替的

显然如果一个边满足只有一个点在 (dfn) 对应的区间里面

那么把对面的树的边的 (dfn) 放到自己这边,每次删除的边放到自己这边搞区间删除

对边的两个端点的 (dfn) 搞一个双射,每次删除一定是区间里面的一个前缀或者后缀,所以线段树维护即可

为了简化代码量,使用了 (std::merge)

这个函数是归并,需要 (st_1,ed_1,st_1,ed_2,back\_inserter()) 五个参数

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define For(i,a,b) for(register int i=a;i<=b;++i)
#define Down(i,a,b) for(register int i=a;i>=b;i--)
#define reg register
inline int min(int x,int y){return x<y?x:y;}
inline int max(int x,int y){return x>y?x:y;}
inline void swap(int &x,int &y){int t=x; x=y; y=t; return ;}
namespace yspm{
	inline int read(){
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	vector<int> ans,tans;
	const int N=2e5+10;
	struct Tree{
		struct node{int nxt,to;}e[N];
		int head[N],in[N],out[N],fa[N],tim,np[N<<2],ns[N<<2],cnt;
		vector<pair<int,int> > pre[N<<2],suf[N<<2];
		bool fl[N];
		inline void add(int u,int v){
			e[++cnt].to=v; e[cnt].nxt=head[u];
			return head[u]=cnt,void();
		}
		inline void dfs(int x,int fat){in[x]=++tim; for(reg int i=head[x];i;i=e[i].nxt) dfs(e[i].to,x); out[x]=tim; return ;}
		inline void build(int p,int l,int r){
			if(l==r){
				sort(pre[p].begin(),pre[p].end()); sort(suf[p].begin(),suf[p].end());
				np[p]=(int)pre[p].size()-1; ns[p]=0; return ;
			}int mid=(l+r)>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r);
			merge(pre[p<<1].begin(),pre[p<<1].end(),pre[p<<1|1].begin(),pre[p<<1|1].end(),back_inserter(pre[p]));
			merge(suf[p<<1].begin(),suf[p<<1].end(),suf[p<<1|1].begin(),suf[p<<1|1].end(),back_inserter(suf[p]));
			np[p]=(int)pre[p].size()-1; ns[p]=0; return ;
		}
		inline void ins(int p,int st,int ed,int pos,int v1,int v2,bool fl){
			if(st==ed) return (!fl)?pre[p].push_back(make_pair(v2,v1)):suf[p].push_back(make_pair(v2,v1)),void();
			int mid=(st+ed)>>1; if(pos<=mid) ins(p<<1,st,mid,pos,v1,v2,fl); else ins(p<<1|1,mid+1,ed,pos,v1,v2,fl);
			return ;
		}
		inline void find(int p,int l,int r,int st,int ed){
			if(st<=l&&r<=ed){
				while(np[p]>=0&&pre[p][np[p]].first>ed){
					if(!fl[pre[p][np[p]].second]) fl[pre[p][np[p]].second]=1,tans.push_back(pre[p][np[p]].second);
					--np[p];
				}
				while(ns[p]<suf[p].size()&&suf[p][ns[p]].first<st){ 
					if(!fl[suf[p][ns[p]].second]) fl[suf[p][ns[p]].second]=1,tans.push_back(suf[p][ns[p]].second);
					++ns[p];
				} return ;
			}int mid=(l+r)>>1; if(st<=mid) find(p<<1,l,mid,st,ed); if(ed>mid) find(p<<1|1,mid+1,r,st,ed); return ;
		}
	}T[2];
	int a[N],b[N],n,fl;
	signed main(){
		freopen("1.in","r",stdin);
		n=read(); for(reg int i=2;i<=n;++i) a[i]=read(),T[0].add(a[i],i); for(reg int i=2;i<=n;++i) b[i]=read(),T[1].add(b[i],i); 
		T[1].dfs(1,0); T[0].dfs(1,0);
		for(reg int i=2;i<=n;++i){
			T[0].ins(1,1,n,min(T[0].in[b[i]],T[0].in[i]),i,max(T[0].in[b[i]],T[0].in[i]),0);
			T[0].ins(1,1,n,max(T[0].in[b[i]],T[0].in[i]),i,min(T[0].in[b[i]],T[0].in[i]),1);
			T[1].ins(1,1,n,min(T[1].in[a[i]],T[1].in[i]),i,max(T[1].in[a[i]],T[1].in[i]),0);
			T[1].ins(1,1,n,max(T[1].in[a[i]],T[1].in[i]),i,min(T[1].in[a[i]],T[1].in[i]),1);
		} T[0].build(1,1,n); T[1].build(1,1,n); int x=read(); ans.push_back(++x); T[1].fl[x]=1; 
		while(ans.size()){
			if(fl) puts("Red"); else puts("Blue"); 
			for(auto p:ans) printf("%lld ",p-1),T[fl].find(1,1,n,T[fl].in[p],T[fl].out[p]); puts("");
			ans=tans; tans.clear(); fl^=1; sort(ans.begin(),ans.end());// assert(ans.size()==2);
		} return 0;
	}
}
signed main(){return yspm::main();}

sum

因为互质,所以每个质因子只会被选一次,那么有以下结论:

((1)) 每个数最多有两个质因子

((2)) 如果有两个质因子,必然是一个大于 (sqrt n) 另一个小于之

感性理解是 (trivial) 的一下

这样的话对每个 (le sqrt n) 的质因子,从 (S) 连流量 (1),费用 (0)

每个 (>sqrt n) 的质因子,连到 (T),流量费用同上

质因子之间如果选择两个优于选择一个那么就连流量 (1),费用 (f(x,y)-f(x)-f(y))

跑最大费用可行流即可

这个就是 (spfa) 改成最长路,如果当前 (d[T]le 0) 就不增广了

bracket

写了仨半小时,点分没还原就爆零了

因为是树上的路径,那么考虑合并两个子树的路径信息

把括号转成 (±1),对于一个前缀,如果其最大值是路径最大/小值,那么最大/小值的出现次数是其 (f(x,y)) 的值

那么按照 ( exttt{SDOI2016模式字符串}) 的思想,维护到 (x) 和从 (x) 出发的值

自贡献可以在处理儿子的时候减掉,和一般的点分是一样的

发现 (f(x,y)=k,f(y,z)=l) 可以贡献给 (f(x,z)=k+l)

对于当前点分子树的信息卷积的时候分着每个和为 (0) 的数组卷即可

实现的时候注意 (dfs) 的时候不能直接修改信息,因为每次统计是一个链,回溯时候要统计的是子树的,需要记一下 (pre)

Dp记录

[min_{Sin A}{frac{M-sum_{xin S} x}{|S|}in{ exttt{Z}}},|A|le 100 ]

枚举最后的选择的集合大小 (sz)

(f[i][j][k]) 为考虑了(i) 个数,选择了 (j) 个,所有的和 (mod sz)(k) 的方案

(Theta(n^4)) 能过的

原文地址:https://www.cnblogs.com/yspm/p/14423825.html