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;
}
话说这一天做仨题也是……主要是湾湾那边搞事太大了,精力不是很集中吧。
明天再接再厉。