海亮寄 7.18

前言

业精于勤荒于嬉,行成于思毁于随

正文(加餐)

树论选讲,这是要 \(DAY^{-1}\) 的节奏

浅贴一个课件

关键词:大杂烩、最优化、树上数据结构

再浅贴一下题单

(好累啊,不想贴代码)

此博客水分含量极高,建议混合海亮食堂的饭菜食用

T1

树上背包板子题

(站在 oier 巨人的肩膀上,被 oi 暴打)

时间复杂度 \(O(n \times \min(n,m))\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=305;
int n,m,head[N],tot,f[N][N];
struct Edge{int to,nxt;}e[N<<1];
inline void add(int u,int v){
    e[++tot]={v,head[u]};head[u]=tot;
    return;
}
inline void dfs(int u,int fa){
    for(int i=head[u];~i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa)continue;
        dfs(v,u);
        for(int j=m+1;j>=1;j--)
            for(int k=0;k<j;k++)
                f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]);
    }
    return;
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    memset(head,-1,sizeof(head));tot=1;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        int x;cin>>x>>f[i][1];
        add(i,x),add(x,i);
    }
    dfs(0,-1);
    cout<<f[0][m+1]<<'\n';
    return 0;
}

T2

我曾经跨过山和大海,却还有比我命长的转移方程在等待

\(f_{u,i,0/1,0/1}\) 表示 \(u\) 子树内消耗了 \(i\) 个监控,自己 不放 / 放 监控,和 不存在 / 存在 儿子放监控的方案数

转移不码了,有脚就行

点击查看代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+5,K=105,MOD=1e9+7;
int n,k,head[N],tot;
struct Edge{int to,nxt;}e[N<<1];
int f[N][K][2][2],g[K][2][2],siz[N];
inline void add(int u,int v){
    e[++tot]={v,head[u]};head[u]=tot;
    return;
}
inline void ADD(int &x,int y){
    x%=MOD,y%=MOD;x=(x*1ll+y*1ll)%MOD;
    return;
}
inline void dfs(int u,int fa){
    f[u][0][0][0]=f[u][1][1][0]=1ll;
    siz[u]=1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa)continue;
        dfs(v,u);
        for(int j=0;j<=min(siz[u],k);j++){
            g[j][0][0]=f[u][j][0][0];f[u][j][0][0]=0ll;
            g[j][0][1]=f[u][j][0][1];f[u][j][0][1]=0ll;
            g[j][1][0]=f[u][j][1][0];f[u][j][1][0]=0ll;
            g[j][1][1]=f[u][j][1][1];f[u][j][1][1]=0ll;
        }
        for(int x=0;x<=min(siz[u],k);x++){
            for(int y=0;y<=min(siz[v],k-x);y++){
                // TMD 这转移方程比我命都长,比 lmy 还 lmy
                ADD(f[u][x+y][0][0],1ll*g[x][0][0]*f[v][y][0][1]%MOD);
                ADD(f[u][x+y][0][1],1ll*g[x][0][0]*f[v][y][1][1]%MOD+1ll*g[x][0][1]*((1ll*f[v][y][0][1]+1ll*f[v][y][1][1])%MOD)%MOD);
                ADD(f[u][x+y][1][0],1ll*g[x][1][0]*((1ll*f[v][y][0][0]+1ll*f[v][y][0][1])%MOD)%MOD);
                ADD(f[u][x+y][1][1],1ll*g[x][1][0]*((1ll*f[v][y][1][0]+1ll*f[v][y][1][1])%MOD)%MOD);
                ADD(f[u][x+y][1][1],1ll*g[x][1][1]*((1ll*f[v][y][0][0]+1ll*f[v][y][0][1]+1ll*f[v][y][1][0]+1ll*f[v][y][1][1])%MOD)%MOD);
            }
        }
        siz[u]+=siz[v];
    }
    return;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>k;
    for(int i=1;i<=n-1;i++){
        int u,v;cin>>u>>v;
        add(u,v),add(v,u);
    }
    dfs(1,0);
    cout<<(f[1][k][0][1]+f[1][k][1][1])%MOD<<'\n';
    return 0;
}

T3

神题(被墨鱼拯救的第一题)

转化一下题意,等价于在树上选出一个连通块,然后在代价和库存都满足不超限的情况下获得最大的收益

这种题容易想到枚举连通块的最高点(子树的根),然后跑有依赖的 DP

这个有依赖的 DP 就很有说法,其依赖关系形如:若父不选,则子不选

推广一下,若某子树根不选,则该子树不选

因此,可以直接把枚举出的子树拍平在 DFS 序列上,并尝试倒序转移

怎么搞呢?首先先二进制拆分让多重背包直接转 01 背包

再记录 \(f_{i,j}\) 表示转移到 dfn 序为 \(i\) 的结点,容量为 \(j\) 的最大值

考虑转移,核心就是决策 dfn 序为 \(i\) 的结点是否入选

入选非常容易,直接从 \(f_{i+1}\) 转移过来

不入选更容易,根据上面的依赖性分析,我们直接略过这个结点的子树,从 \(f_{i+sz[rev[i]]}\) 转移即可

时间复杂度 \(O(\text{不能过})\),咳咳准确来说是 \(O(T \times n^2 \times m \times \log V)\)

然后,就有了如下场景:

墨鱼:你看 \(O(n^2 \times m \times \log V)\) 是不是过不了
云落:(作沉思状)
墨鱼:别跟我说卡常,反正就是过不了
云落:嗯,好
墨鱼:你看前面这个枚举子树的操作,你想到了什么?
云落:嗯……?(走神)
墨鱼:嗯!想到什么了?
云落:呃,哦!
墨鱼:想到什么了?
云落:(沉默)
墨鱼:点分治啊!

没错这个题就是把枚举子树根的操作改装成点分治这种神秘的东西,就可以草过去咯!

(有点神秘)

像树上这种找连通块问题,墨鱼表示点分治是非常好用的,比如 首都 这道题目

因为它保证了跨子树的信息要么一定已经被计算过了,要么就是跨子树信息总是不能对答案造成贡献

时间复杂度 \(O(\text{能过})\),咳咳准确来说是 \(O(T \times n \log n \times m \log V)\)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=505,M=4e3+5,INF=2e9;
int n,m,w[N],c[N],d[N],head[N],tot,ans;
struct Edge{int to,nxt,val;}e[N<<1];
int siz[N];bool vis[N];int L[N],tim,rev[N],R[N];
int f[N][M];struct node{int v,w;}a[N];
inline void add(int u,int v){
    e[++tot]={v,head[u]};head[u]=tot;
    return;
}
inline void getsz(int u,int fa){
    siz[u]=1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa||vis[v])continue;
        getsz(v,u);siz[u]+=siz[v];
    }
    return;
}
inline void getzx(int u,int fa,int rt,int &mn,int &g){
    int sub=siz[rt]-siz[u];
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa||vis[v])continue;
        sub=max(sub,siz[v]);
        getzx(v,u,rt,mn,g);
    }
    if(sub<mn)mn=sub,g=u;
    return;
}
inline void dfs(int u,int fa){
    L[u]=++tim;rev[tim]=u;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa||vis[v])continue;
        dfs(v,u);
    }
    R[u]=tim;
    return;
}
inline void divide(int u){
    getsz(u,0);
    int mn=INF,g=0;
    getzx(u,0,u,mn,g);vis[g]=true;    
    memset(L,0,sizeof(L));tim=0;
    memset(rev,0,sizeof(rev));memset(R,0,sizeof(R));
    dfs(g,0);
    for(int i=tim;i>=1;i--){
        int nd=rev[i],lim=d[nd]-1,idx=0,x=1;
        while(x<=lim){
            a[++idx]={w[nd]*x,c[nd]*x};
            lim-=x,x<<=1;
        }
        if(lim)a[++idx]={w[nd]*lim,c[nd]*lim};
        for(int j=m;j>=c[nd];j--)f[i][j]=f[i+1][j-c[nd]]+w[nd];
        for(int x=1;x<=idx;x++)
            for(int j=m;j>=a[x].w;j--)
                f[i][j]=max(f[i][j],f[i][j-a[x].w]+a[x].v);
        for(int j=0;j<=m;j++)f[i][j]=max(f[i][j],f[R[rev[i]]+1][j]);
    }
    ans=max(ans,f[1][m]);
    for(int i=1;i<=tim;++i)
        for(int j=0;j<=m;++j)
            f[i][j]=0;
    for(int i=head[g];i;i=e[i].nxt){
        int v=e[i].to;
        if(vis[v])continue;
        divide(v);
    }
    return;
}
inline void solve(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>w[i];
    for(int i=1;i<=n;i++)cin>>c[i];
    for(int i=1;i<=n;i++)cin>>d[i];
    for(int i=1;i<=n-1;i++){
        int u,v;cin>>u>>v;
        add(u,v),add(v,u);
    }
    divide(1);
    cout<<ans<<'\n';
    return;
}
inline void clr(){
    memset(head,0,sizeof(head));tot=1;
    memset(vis,false,sizeof(vis));
    ans=0;
    return;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int T;cin>>T;while(T--)solve(),clr();    
    return 0;
}

T4

不会(恼)

T5

无聊的贪心,二分答案显然

问题转化为尽可能多的选择合法路径,并判定个数是否 \(\ge m\)

观察发现,对于 \((u,fa)\) 的边来说,至多只有一个 \(u\) 的儿子 \(v\) 可以使用

所以记 \(dis_v\) 表示 \(v\) 子树内已经处理完毕并且可以向上转移的路径长度

\(u\) 这一层中,直接把所有 \(v\) 都塞到 multiset 中。先内部消化(即两两配对。具体地,从小到大遍历,用 lower_bound 去找可以配对的 \((dis_v,dis_{v'})\)。然后在剩余未配对成功的 \(dis_v\) 中选取一个最大值,作为代表贡献给 \(dis_u\),参与更高一层的路径信息处理

(日常不会用 multiset,菜完了简直)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e4+5,INF=1e9;
int n,m,head[N],tot;
struct Edge{int to,nxt,val;}e[N<<1];
int dis[N];multiset<int> S;
inline void add(int u,int v,int w){
    e[++tot]={v,head[u],w};head[u]=tot;
    return;
}
inline int dfs(int u,int fa,int lim){
    int res=0;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(v==fa)continue;
		res+=dfs(v,u,lim);
	}
	S.clear();
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to,w=e[i].val;
		if(v==fa)continue;
		dis[v]+=w;
		if(dis[v]>=lim)res++;
		else S.insert(dis[v]);
	}
	dis[u]=0;
	while(!S.empty()){
		int x=*S.begin();S.erase(S.begin());
		auto it=S.lower_bound(lim-x);
		if(it!=S.end())res++,S.erase(it);
		else dis[u]=max(dis[u],x);
	}
	return res;
}
inline bool check(int mid){
    for(int i=1;i<=n;i++)dis[i]=0;
    return dfs(1,0,mid)>=m;
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n-1;i++){
        int u,v,w;cin>>u>>v>>w;
        add(u,v,w),add(v,u,w);
    }
    int l=1,r=INF,ans=1;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid))l=mid+1,ans=mid;
        else r=mid-1;
    }
    cout<<ans<<'\n';
    return 0;
}

T6

点击查看代码
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int maxn=1e5+10;
int n,m,rt,p,a[maxn];
vector<int> G[maxn];
int fa[maxn],son[maxn],dep[maxn],sz[maxn];
int dfn[maxn],tim,Top[maxn],rev[maxn];
struct Segment_tree{
	struct node{
		int l,r,sum,tag;
	}tr[maxn<<2];
	void pushup(int u){
		tr[u].sum=(tr[u<<1].sum+tr[u<<1|1].sum)%p;
		return;
	}
	void pushdown(int u){
		if(tr[u].tag==0){
			return;
		}
		int k=tr[u].tag;
		tr[u<<1].sum=(tr[u<<1].sum+k*(tr[u<<1].r-tr[u<<1].l+1)%p)%p;
		tr[u<<1|1].sum=(tr[u<<1|1].sum+k*(tr[u<<1|1].r-tr[u<<1|1].l+1)%p)%p;
		tr[u<<1].tag=(tr[u<<1].tag+k)%p;
		tr[u<<1|1].tag=(tr[u<<1|1].tag+k)%p;
		tr[u].tag=0;
		return;
	}
	void build(int u,int l,int r){
		tr[u].l=l;
		tr[u].r=r;
		if(l==r){
			tr[u].sum=rev[l]%p;
			return;
		}
		int mid=l+r>>1;
		build(u<<1,l,mid);
		build(u<<1|1,mid+1,r);
		pushup(u);
		return;
	}
	void modify(int u,int ql,int qr,int k){
		int l=tr[u].l,r=tr[u].r;
		if(ql<=l&&qr>=r){
			tr[u].sum=(tr[u].sum+k*(r-l+1)%p)%p;
			tr[u].tag=(tr[u].tag+k)%p;
			return;
		}
		pushdown(u);
		int mid=l+r>>1;
		if(ql<=mid){
			modify(u<<1,ql,qr,k);
		}
		if(qr>mid){
			modify(u<<1|1,ql,qr,k);
		}
		pushup(u);
		return;
	}
	int query(int u,int ql,int qr){
		int l=tr[u].l,r=tr[u].r;
		if(ql<=l&&qr>=r){
			return tr[u].sum%p;
		}
		pushdown(u);
		int mid=l+r>>1,res=0;
		if(ql<=mid){
			res=(res+query(u<<1,ql,qr))%p;
		}
		if(qr>mid){
			res=(res+query(u<<1|1,ql,qr))%p;
		}
		return res%p;
	}
}Tr;
inline void dfs1(int u,int fath){
	fa[u]=fath;
	dep[u]=dep[fath]+1;
	sz[u]=1;
	int mx=-1;
	for(int v:G[u]){
		if(v==fath){
			continue;
		}
		dfs1(v,u);
		sz[u]+=sz[v];
		if(sz[v]>mx){
			mx=sz[v];
			son[u]=v;
		}
	}
	return;
}
inline void dfs2(int u,int tp){
	dfn[u]=++tim;
	Top[u]=tp;
	rev[tim]=a[u];
	if(!son[u]){
		return;
	}
	dfs2(son[u],tp);
	for(int v:G[u]){
		if(v==fa[u]||v==son[u]){
			continue;
		}
		dfs2(v,v);
	}
	return;
}
inline void update_chain(int u,int v,int w){
	w%=p;
	while(Top[u]!=Top[v]){
		if(dep[Top[u]]<dep[Top[v]]){
			swap(u,v);
		}
		Tr.modify(1,dfn[Top[u]],dfn[u],w);
		u=fa[Top[u]];
	}
	if(dep[u]>dep[v]){
		swap(u,v);
	}
	Tr.modify(1,dfn[u],dfn[v],w);
	return;
}
inline int query_chain(int u,int v){
	int res=0;
	while(Top[u]!=Top[v]){
		if(dep[Top[u]]<dep[Top[v]]){
			swap(u,v);
		}
		res=(res+Tr.query(1,dfn[Top[u]],dfn[u]))%p;
		u=fa[Top[u]];
	}
	if(dep[u]>dep[v]){
		swap(u,v);
	}
	res=(res+Tr.query(1,dfn[u],dfn[v]))%p;
	return res;
}
inline void update_subtree(int u,int k){
	k%=p;
	Tr.modify(1,dfn[u],dfn[u]+sz[u]-1,k);
	return;
}
inline int query_subtree(int u){
	int res=Tr.query(1,dfn[u],dfn[u]+sz[u]-1)%p;
	return res;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m>>rt>>p;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n-1;i++){
		int u,v;
		cin>>u>>v;
		G[u].push_back(v);
		G[v].push_back(u);
	}
	dfs1(rt,0);
	dfs2(rt,rt);
	Tr.build(1,1,n);
	for(int k=1;k<=m;k++){
		int opt;
		cin>>opt;
		if(opt==1){
			int x,y,z;
			cin>>x>>y>>z;
			update_chain(x,y,z);
		}else if(opt==2){
			int x,y;
			cin>>x>>y;
			int ans=query_chain(x,y)%p;
			cout<<ans<<endl;
		}else if(opt==3){
			int x,z;
			cin>>x>>z;
			update_subtree(x,z);
		}else if(opt==4){
			int x;
			cin>>x;
			int ans=query_subtree(x)%p;
			cout<<ans<<endl;
		}
	}
	return 0;
}

T7

\(\times 2\)

点击查看代码
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N=1e6+5,INF=0x3f3f3f3f;
int n,m,rt,w[N],head[N],tot;
struct Edge{int to,nxt;}e[N<<1];
struct Matrix{
    int a[2][2];
    friend Matrix operator * (Matrix A,Matrix B){
        Matrix C;
        C.a[0][0]=C.a[0][1]=C.a[1][0]=C.a[1][1]=-INF;
        C.a[0][0]=max(A.a[0][0]+B.a[0][0],A.a[0][1]+B.a[1][0]);
        C.a[0][1]=max(A.a[0][0]+B.a[0][1],A.a[0][1]+B.a[1][1]);
        C.a[1][0]=max(A.a[1][0]+B.a[0][0],A.a[1][1]+B.a[1][0]);
        C.a[1][1]=max(A.a[1][0]+B.a[0][1],A.a[1][1]+B.a[1][1]);
        return C;
    }
}A[N],B[N];
int dep[N],son[N],siz[N],lsiz[N];
int f[N][2],g[N][2],trfa[N],ls[N],rs[N];
int stk[N],tp;
bool vis[N];
inline void add(int u,int v){e[++tot]={v,head[u]};head[u]=tot;return;}
inline void dfs(int u,int fa){
    siz[u]=1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa)continue;
        dfs(v,u);siz[u]+=siz[v];
        if(siz[v]>siz[son[u]])son[u]=v;
    }
    lsiz[u]=siz[u]-siz[son[u]];
    return;
}
inline void init(int u,int fa){
    if(son[u])init(son[u],u);
    g[u][1]=w[u];
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa||v==son[u])continue;
        init(v,u);
        g[u][0]+=max(f[v][0],f[v][1]);
        g[u][1]+=f[v][0];
    }
    f[u][0]=g[u][0]+max(f[son[u]][0],f[son[u]][1]);
	f[u][1]=g[u][1]+f[son[u]][0];
    return;
}
inline void pushup(int u){
    B[u]=A[u];
    if(ls[u])B[u]=B[ls[u]]*B[u];
    if(rs[u])B[u]=B[u]*B[rs[u]];
    return;
}
inline int Sbuild(int l,int r){
    if(l>r)return 0;
    int sum=0;
    for(int i=l;i<=r;i++)sum+=lsiz[stk[i]];
    int tmp=0;
    for(int i=l;i<=r;i++){
        tmp+=lsiz[stk[i]];
        if(tmp*2>=sum){
            int u=stk[i],lch=Sbuild(l,i-1),rch=Sbuild(i+1,r);
            ls[u]=lch;rs[u]=rch; trfa[lch]=trfa[rch]=u;
            pushup(u);
            return u;
        }
    }
    return 0;
}
inline int build(int u){
    for(int x=u;x;x=son[x])vis[x]=true;
    for(int x=u;x;x=son[x]){
        for(int i=head[x];i;i=e[i].nxt){
            int v=e[i].to;
            if(vis[v])continue;
            trfa[build(v)]=x;
        }
    }
    tp=0;
    for(int x=u;x;x=son[x])stk[++tp]=x;
    return Sbuild(1,tp);
}
inline int getmx2(int u){return max(B[u].a[0][0],B[u].a[0][1]);}
inline int getmx1(int u){return max(getmx2(u),B[u].a[1][0]);}
inline void upd(int u,int v){
    A[u].a[1][0]+=(v-w[u]);w[u]=v;
    for(int x=u;x;x=trfa[x]){
        if(trfa[x]&&ls[trfa[x]]!=x&&rs[trfa[x]]!=x){
            A[trfa[x]].a[0][0]-=getmx1(x);
            A[trfa[x]].a[0][1]=A[trfa[x]].a[0][0];
            A[trfa[x]].a[1][0]-=getmx2(x);
            pushup(x);
            A[trfa[x]].a[0][0]+=getmx1(x);
            A[trfa[x]].a[0][1]=A[trfa[x]].a[0][0];
            A[trfa[x]].a[1][0]+=getmx2(x);
        }else pushup(x);
    }
    return;
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>w[i];
    for(int i=1;i<=n-1;i++){
        int u,v;cin>>u>>v;
        add(u,v);add(v,u);
    }
    dfs(1,-1);init(1,-1);
    for(int i=1;i<=n;i++){
        A[i].a[0][0]=A[i].a[0][1]=g[i][0];
        A[i].a[1][0]=g[i][1];A[i].a[1][1]=-INF;
    }
    rt=build(1);
    int lst=0;
    while(m--){
        int u,v;cin>>u>>v;u^=lst;
        upd(u,v);lst=getmx1(rt);
        cout<<lst<<endl;
    }
    return 0;
}

T8

花絮时间

云落:“非板,好耶!”

(省略一个看题过程)

系统提示:云落撤回了一条消息

正片开始

把树上对应的那一层抓出来,子树的限制直接转化为 dfn 的限制

对于符合所有限制的结点,直接哈希并异或起来判断即可

(无聊)

点击查看代码
#include<bits/stdc++.h>
#define vi vector<int>
#define pb push_back
#define lwbd lower_bound
#define upbd upper_bound
using namespace std;
const int N=5e5+1;
int n,m,head[N],tot;string s;
struct Edge{int to,nxt;}e[N<<1];
int L[N],tim,rev[N],dep[N],R[N];
int mx;vi vec[N],sum[N];
inline void add(int u,int v){
    e[++tot]={v,head[u]};head[u]=tot;
    return;
}
inline void dfs(int u,int fa){
    L[u]=++tim;rev[tim]=u;dep[u]=dep[fa]+1;
    mx=max(mx,dep[u]);vec[dep[u]].pb(L[u]);
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa)continue;
        dfs(v,u);
    }
    R[u]=tim;
    return;
}
inline void solve(){
    int v,h;cin>>v>>h;
    int l=lwbd(vec[h].begin(),vec[h].end(),L[v])-vec[h].begin();
	int r=upbd(vec[h].begin(),vec[h].end(),R[v])-vec[h].begin()-1;
    if(r<0){cout<<"Yes\n";return;}
    int ans=(l==0?sum[h][r]:sum[h][r]^sum[h][l-1]);
    int num=__builtin_popcount(ans);
    cout<<(num==1||num==0?"Yes\n":"No\n");
    return;
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=2;i<=n;i++){
        int x;cin>>x;
        add(i,x),add(x,i);
    }
    cin>>s;s=' '+s;
    dfs(1,0);
    for(int d=1;d<=mx;d++){
        sum[d].pb(1<<(s[rev[vec[d][0]]]-'a'));
        int _size=vec[d].size();
        for(int i=1;i<=_size-1;i++){
            int val=(1<<(s[rev[vec[d][i]]]-'a'));
            sum[d].pb(sum[d][i-1]^val);
        }
    }
    while(m--)solve();
    return 0;
}

T9

\(\times 3\)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5,M=105,K=1e7+5,INF=2e9;
int n,m,Q[M],head[N],tot,ans[M];
struct Edge{int to,nxt,val;}e[N<<1];
int siz[N];bool vis[N];
int dis[N],cnt,t[N],tol;bool mrk[K];
inline void add(int u,int v,int w){
    e[++tot]={v,head[u],w};head[u]=tot;
    return;
}
inline void getsz(int u,int fa){
    siz[u]=1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa||vis[v])continue;
        getsz(v,u);siz[u]+=siz[v];
    }
    return;
}
inline void getzx(int u,int fa,int rt,int &mn,int &g){
    int sub=siz[rt]-siz[u];
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa||vis[v])continue;
        sub=max(sub,siz[v]);
        getzx(v,u,rt,mn,g);
    }
    if(sub<mn)mn=sub,g=u;
    return;
}
inline void dfs(int u,int fa,int depth){
    if(depth<=1e7)t[++tol]=depth;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to,w=e[i].val;
        if(v==fa||vis[v])continue;
        dfs(v,u,depth+w);
    }
    return;
}
inline void solve(int u){
    getsz(u,0);
    int mn=INF,g=0;
    getzx(u,0,u,mn,g);vis[g]=true;
    mrk[0]=true;cnt=0;dis[++cnt]=0;
    for(int i=head[g];i;i=e[i].nxt){
        int v=e[i].to,w=e[i].val;
        if(vis[v])continue;
        tol=0;dfs(v,g,w);
        for(int x=1;x<=tol;x++)
            for(int y=1;y<=m;y++)
                if(Q[y]>=t[x])ans[y]|=mrk[Q[y]-t[x]];
        for(int x=1;x<=tol;x++){
            dis[++cnt]=t[x];
            if(t[x]<=1e7)mrk[t[x]]=true;
        }            
    }
    for(int i=1;i<=cnt;i++)
        if(dis[i]<=1e7)mrk[dis[i]]=false;
    for(int i=head[g];i;i=e[i].nxt){
        int v=e[i].to;
        if(vis[v])continue;
        solve(v);
    }
    return;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n-1;i++){
        int u,v,w;cin>>u>>v>>w;
        add(u,v,w),add(v,u,w);
    }
    for(int i=1;i<=m;i++)cin>>Q[i];
    solve(1);
    for(int i=1;i<=m;i++)cout<<(ans[i]?"AYE\n":"NAY\n");
    return 0;
}

T10

\(\times 10086\),但是不会

被墨鱼拯救的第二题,但暂时不想写算法梳理

先挖个坑,以后再填

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,K=18,INF=0x3f3f3f3f;
int n,Q,a[N],head[N],tot;
struct Edge{int to,nxt;}e[N<<1];
int dep[N],dfn[N<<1],tim,bra[N<<1];
int siz[N],dfa[N];bool vis[N];
struct Sparse_table{
	int lg[N<<1],f[N<<1][K];
	inline int MIN(int x,int y){return dep[x]<dep[y]?x:y;}
	inline void init(){
		lg[0]=-1;
		for(int i=1;i<=tim;i++)lg[i]=lg[i>>1]+1;
		for(int i=1;i<=tim;i++)f[i][0]=bra[i];
		for(int j=1;j<=lg[tim];j++)
			for(int i=1;i+(1<<j)<=tim;i++)
				f[i][j]=MIN(f[i][j-1],f[i+(1<<(j-1))][j-1]);
		return;
	}
	inline int ask(int l,int r){
		int p=lg[r-l+1];
		return MIN(f[l][p],f[r-(1<<p)+1][p]);
	}
}ST;
struct Segment_tree{
	int rt[N],cnt=0;
	struct node{int l,r,sum;}tr[N<<6];
    inline void pushup(int u){
        tr[u].sum=(tr[tr[u].l].sum+tr[tr[u].r].sum);
        return;
    }
	inline void modify(int &u,int l,int r,int pos,int v){
        if(!u)u=++cnt;
        if(l==r){tr[u].sum+=v;return;}
		int mid=(l+r)>>1;
		if(pos<=mid)modify(tr[u].l,l,mid,pos,v);
		else modify(tr[u].r,mid+1,r,pos,v);
        pushup(u);
	}
	inline int query(int u,int l,int r,int ql,int qr){
		if(!u)return 0;
		if(ql<=l&&r<=qr)return tr[u].sum;
		int mid=(l+r)>>1;
		if(qr<=mid)return query(tr[u].l,l,mid,ql,qr);
		if(ql>mid)return query(tr[u].r,mid+1,r,ql,qr);
		return query(tr[u].l,l,mid,ql,mid)+query(tr[u].r,mid+1,r,mid+1,qr);
	}
}sgt1,sgt2;
inline void add(int u,int v){
	e[++tot]={v,head[u]};head[u]=tot;
	return;
}
inline void dfs(int u,int fath){
	dep[u]=dep[fath]+1;dfn[u]=++tim;
	bra[tim]=u;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(v==fath)continue;
		dfs(v,u);bra[++tim]=u;
	}
	return;
}
inline int LCA(int x,int y){
	if(x==y)return x;
	if(dfn[x]>dfn[y])swap(x,y);
	x=dfn[x];y=dfn[y];
	return ST.ask(x,y);
}
inline int getdis(int x,int y){return dep[x]+dep[y]-dep[LCA(x,y)]*2;}
inline void getsz(int u,int fa){
    siz[u]=1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa||vis[v])continue;
        getsz(v,u);siz[u]+=siz[v];
    }
    return;
}
inline void getzx(int u,int fa,int rt,int &mn,int &g){
    int sub=siz[rt]-siz[u];
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa||vis[v])continue;
        sub=max(sub,siz[v]);
        getzx(v,u,rt,mn,g);
    }
    if(sub<mn)mn=sub,g=u;
    return;
}
inline void divide(int u,int DFA){
    getsz(u,0);
    int mn=INF,g=0;
    getzx(u,0,u,mn,g);vis[g]=true;dfa[g]=DFA;
    for(int i=head[g];i;i=e[i].nxt){
        int v=e[i].to;
        if(vis[v])continue;
        divide(v,g);
    }
    return;
}
inline void upd(int u,int v){
	int now=u;
	while(now){
		sgt1.modify(sgt1.rt[now],0,n-1,getdis(now,u),v);
		if(dfa[now])sgt2.modify(sgt2.rt[now],0,n-1,getdis(dfa[now],u),v);
		now=dfa[now];
	}
    return;
}
inline int ask(int u,int k){
    int now=u,pre=0,res=0;
    while(now){
        if(getdis(now,u)<=k){
            res+=sgt1.query(sgt1.rt[now],0,n-1,0,k-getdis(now,u));
            if(pre)res-=sgt2.query(sgt2.rt[pre],0,n-1,0,k-getdis(now,u));
        }
		pre=now;now=dfa[now];
    }
    return res;
}
signed main(){
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>Q;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n-1;i++){
        int u,v;cin>>u>>v;
        add(u,v),add(v,u);
    }
    dfs(1,0);ST.init();divide(1,0);
    for(int i=1;i<=n;i++)upd(i,a[i]);
    int lst=0;
    while(Q--){
        int opt,x,y;cin>>opt>>x>>y;
        x^=lst,y^=lst;
        if(opt==0)cout<<(lst=ask(x,y))<<'\n';
        else upd(x,y-a[x]),a[x]=y;
    }
    return 0;
}

T11

还是不会,菜完了

STO 软软 orz

后记

世界孤立我任它奚落

完结撒花!

posted @ 2025-07-21 09:32  sunxuhetai  阅读(5)  评论(0)    收藏  举报