8月2日做题日记

8.2 刷题日记

P6591 [YsOI2020]植树

换根法,处理子树大小,然后看子树大小一不一样就行。

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define debug cout<<"Szt ak ioi\n";
//#define int long long

const int Mod=1e9+7;
const int N=1e6+7,M=2e3+1;

using namespace std;

inline int read() {
	int x=0,f=0;
	char ch=getchar();
	while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
	while(isdigit(ch))x=(x<<1)+(x<<3)+(ch&15),ch=getchar();
	return f?-x:x;
}

int n,Size[N];
vector<int>G[N],Ans;

void dfs1(int u,int fa){
	Size[u]=1;
	for(auto &v:G[u]){
		if(v==fa) continue;
		dfs1(v,u);Size[u]+=Size[v];
	}
}

void dfs2(int u,int fa){
	int Jg=Size[G[u][0]],flg=0;
	for(auto &v:G[u]){if(Size[v]!=Jg){flg=1;break;}}
	if(!flg) Ans.push_back(u);
	for(auto &v:G[u]){
		if(v==fa) continue;
		Size[u]-=Size[v];Size[v]+=Size[u];
		dfs2(v,u);
		Size[v]-=Size[u];Size[u]+=Size[v];
	}
}

signed main() {
	n=read();
	if(n==1) return cout<<1,0;
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		G[u].push_back(v);
		G[v].push_back(u);
	}dfs1(1,0);dfs2(1,0);
	sort(Ans.begin(),Ans.end());
	for(auto &i:Ans) printf("%d ",i);
	return 0;
}

P4211 [LNOI2014]LCA

树剖,思维?为什么一离线我就不会啊。

一看式子:\(\displaystyle \sum_{i=l}^r dep_{Lca(i,z)}\),马上差分,\(\displaystyle\sum_{i=1}^{r}dep_{Lca(i,z)}- \sum_{i=1}^{l-1}dep_{Lca(i,z)}\)\(dep\) 其实就是到根的距离,那就是看每个点贡献了多少,越下的点贡献的越多,并且是累加的,直接树剖。

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define debug cout<<"Szt ak ioi\n";
//#define int long long

const int Mod=201314;
const int N=1e6+7,M=2e3+1;

using namespace std;

inline int read() {
	int x=0,f=0;
	char ch=getchar();
	while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
	while(isdigit(ch))x=(x<<1)+(x<<3)+(ch&15),ch=getchar();
	return f?-x:x;
}

int n,m;
namespace Seg{
	#define lson pos<<1
	#define rson pos<<1|1
	struct Tree{int sum,lazy,len;}tree[N];

	void push_down(int pos){
		if(!tree[pos].lazy) return;
		tree[lson].lazy+=tree[pos].lazy;
		tree[rson].lazy+=tree[pos].lazy;
		tree[lson].sum+=tree[lson].len*tree[pos].lazy;
		tree[rson].sum+=tree[rson].len*tree[pos].lazy;
		tree[lson].lazy%=Mod;tree[rson].lazy%=Mod;
		tree[lson].sum%=Mod;tree[rson].sum%=Mod;
		tree[pos].lazy=0;
	}
	
	void build(int pos,int l,int r){
		tree[pos].len=r-l+1;
		if(l==r) return;int mid=l+r>>1;
		build(lson,l,mid);build(rson,mid+1,r);
	}
	
	void Modify(int pos,int l,int r,int L,int R){
//		debug
		if(l>=L&&r<=R) return tree[pos].sum+=tree[pos].len,tree[pos].lazy++,void();
		int mid=l+r>>1;push_down(pos);
		if(L<=mid) Modify(lson,l,mid,L,R);
		if(R>mid) Modify(rson,mid+1,r,L,R);
		tree[pos].sum=(tree[lson].sum+tree[rson].sum)%Mod;
	}
	
	int Query(int pos,int l,int r,int L,int R){
		if(l>=L&&r<=R) return tree[pos].sum;
		int mid=l+r>>1,res=0;push_down(pos);
		if(L<=mid) res+=Query(lson,l,mid,L,R),res%=Mod;
		if(R>mid) res+=Query(rson,mid+1,r,L,R),res%=Mod;
		return res%Mod;
	}
}

int Size[N],son[N],fath[N],dep[N],dfn[N],top[N],idx;
vector<int>G[N];
namespace Cut{
	void dfs1(int u,int fa){
		fath[u]=fa;Size[u]=1;dep[u]=dep[fa]+1;
		for(auto &v:G[u]){
			if(v==fa) continue;
			dfs1(v,u);
			Size[u]+=Size[v];
			if(Size[v]>Size[son[u]]) son[u]=v;
		}
	}
	
	void dfs2(int u,int tp){
		top[u]=tp;dfn[u]=++idx;
		if(son[u]) dfs2(son[u],tp);
		for(auto &v:G[u]){
			if(v==fath[u]||v==son[u]) continue;
			dfs2(v,v);
		}
	}
	
	void Modify(int u,int v){
		while(top[u]!=top[v]){
//			debug
			if(dep[top[v]]>dep[top[u]]) swap(u,v);
			Seg::Modify(1,1,n,dfn[top[u]],dfn[u]);
			u=fath[top[u]];
		}
		if(dep[v]<dep[u]) swap(u,v);
		Seg::Modify(1,1,n,dfn[u],dfn[v]);
	}
	
	int Query(int u,int v){
		int res=0;
		while(top[u]!=top[v]){
			if(dep[top[v]]>dep[top[u]]) swap(u,v);
			res+=Seg::Query(1,1,n,dfn[top[u]],dfn[u]);
			u=fath[top[u]];res%=Mod;
		}
		if(dep[v]<dep[u]) swap(u,v);
		res+=Seg::Query(1,1,n,dfn[u],dfn[v]);
		return res%Mod;
	}
}

struct node{int pre,z,bh;bool type;};
node A[N];int sc;

bool cmp(node a,node b){return a.pre<b.pre;}

int res1[N],res2[N];

signed main() {
	n=read(),m=read();
	for(int i=2;i<=n;i++){
		int fa=read()+1;
		G[fa].push_back(i);
		G[i].push_back(fa);
	}
	Cut::dfs1(1,0),Cut::dfs2(1,1);Seg::build(1,1,n);
	for(int i=1;i<=m;i++){
		int l=read()+1,r=read()+1,z=read()+1;
		A[++sc]=(node){l-1,z,i,0};
		A[++sc]=(node){r,z,i,1};
	}
	sort(A+1,A+sc+1,cmp);
//	for(int i=1;i<=sc;i++) cout<<A[i].bh<<" ";
	for(int i=1,pos=0;i<=sc;i++){
		while(pos<A[i].pre)++pos,Cut::Modify(1,pos);
		(A[i].type?res1[A[i].bh]:res2[A[i].bh])=Cut::Query(1,A[i].z);
	}
	for(int i=1;i<=m;i++) printf("%d\n",(res1[i]-res2[i]+Mod)%Mod);
	return 0;
}

树剖忘记处理 dep 数组导致调了两个小时,警钟敲烂。

P2606 [ZJOI2010]排列计数

组合数问题。

看这个式子,其实就是一棵树,然后还要小根堆,那么就是说根节点占一个,然后剩下的 \(i-1\) 个节点再选出 \(l\) 个来当左子树,剩下的当右子树,即:\(f[i]=C_{i-1}^{l} \times f[l] \times f[r]\),然后处理一下组合数,Lucas 一搞就行了。

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define debug cout<<"Szt ak ioi\n";
#define int long long

int Mod;
const int N=4e6+7,M=2e3+1;

using namespace std;

inline int read() {
	int x=0,f=0;
	char ch=getchar();
	while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
	while(isdigit(ch))x=(x<<1)+(x<<3)+(ch&15),ch=getchar();
	return f?-x:x;
}

int n,fac[N],Size[N],f[N],inv[N];

int Pow(int a,int b){
	int res=1;a%=Mod;
	while(b){
		if(b&1) res=(res*a)%Mod;
		b>>=1;a=(a*a)%Mod;
	}
	return res;
}

void Fac(){
	fac[0]=1,inv[1]=1;
	for(int i=1;i<=n;i++) f[i<<1]=f[i<<1|1]=Size[i]=1,fac[i]=(fac[i-1]*i)%Mod;
	for(int i=n;i>=2;i--) Size[i>>1]+=Size[i];
}

int C(int a,int b){
	if(a<b) return 0;
	return fac[a]*Pow(fac[b],Mod-2)%Mod*Pow(fac[a-b],Mod-2)%Mod;
}

int Lucas(int x,int y){
	if(!y) return 1;
	return C(x%Mod,y%Mod)*Lucas(x/Mod,y/Mod)%Mod;
}

signed main() {
	n=read(),Mod=read();Fac();
	for(int i=n;i>=1;i--) f[i]=Lucas(Size[i]-1,Size[i<<1])*f[i<<1]%Mod*f[i<<1|1]%Mod;
	printf("%lld\n",f[1]);
	return 0;
}

话说这一天做仨题也是……主要是湾湾那边搞事太大了,精力不是很集中吧。

明天再接再厉。

posted @ 2022-08-02 21:54  Gym_nastics  阅读(24)  评论(0编辑  收藏  举报