[JZOJ NOIP2018模拟10.19]

T1写炸了今天,期望70却落了个20...连链上的都没有写对

T3什么什么线段树分治套AC自动机,表示我完全自闭了,幸好考场上没有杠T3

总体比赛还是比较舒服,暴力分给的蛮足的,不像昨天那样


T1:林下风气 

题目链接:

http://172.16.0.132/senior/#main/show/5913

题目:

里口福因有林下风气,带领全国各地高校掀起了一股AK风,大家都十分痴迷于AK。里口福为了打击大家的自信心,出了一道自以为十分困难的题目。
里口福有一棵树,第i个节点上有点权ai,他的问题就是这棵树中有多少个不同的连通块满足连通块的最大值与最小值之差=k,两个连通块不同当且仅当至少存在一个节点在一个连通块中出现而另一个连通块中没有出现。
痴迷于AK的你马上接下这道题目,在里口福狂妄的笑声中,你切掉这道题的决心更加坚定了,现在就差你的代码了。

题解:

我们枚举一下最小值,这样最大值就是唯一确定的了

以最小值为根跑$dp$,$dp(x,r,k)$表示最小值是$a[r]$,当前在$x$节点,最大值和最小值之差不超过$k$的连通块的个数

当$a[r]<=a[y]<=a[r]+k$时可以转移

发现这样以两个a值相等的点为根可能方案会算重,所以当$a[r]==a[y]$时我们强制让y<r的时候才可以转移

显然若当前枚举的最小值为a[i],对答案的贡献就是$dp(i,i,k)-dp(i,i,k-1)$

#include<algorithm>
#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;

const int N=3333+15;
const int mo=19260817;
int n,k,tot;
int a[N],head[N];
struct E{
    int to,nxt;
}edge[N<<1];
inline int read()
{
    char ch=getchar();
    int s=0,f=1;
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*f;
}
void link(int u,int v){edge[++tot]=(E){v,head[u]};head[u]=tot;}
int dp(int x,int pre,int r,int k)
{
    if (k<0) return 0;
    int re=1;
    for (int i=head[x];i;i=edge[i].nxt)
    {
        int y=edge[i].to;
        if (y==pre) continue;
        if (a[y]>=a[r]&&a[y]<=a[r]+k&&(a[y]!=a[r]||(a[y]==a[r]&&y<r))) 
        {
            re=1ll*re*(dp(y,x,r,k)+1)%mo;
        }
    }
    return re;
}
int main()
{
    freopen("lkf.in","r",stdin);
    freopen("lkf.out","w",stdout);
    n=read();k=read();
    for (int i=1;i<=n;i++) a[i]=read();
    for (int i=1,u,v;i<n;i++){
        u=read();v=read();
        link(u,v);link(v,u);
    }
    int ans=0;
    for (int i=1;i<=n;i++)
    {
        ans=(ans+((dp(i,0,i,k)-dp(i,0,i,k-1))%mo+mo)%mo)%mo;
    }
    printf("%d
",ans);
    return 0;
}
View Code

T2:盟主的忧虑 

 题目链接:

http://172.16.0.132/senior/#contest/show/2531/0

题目:

里口福因有林下风气,带领全国各地高校掀起了一股AK风,大家都十分痴迷于AK。里口福为了打击大家的自信心,出了一道自以为十分困难的题目。
里口福有一棵树,第i个节点上有点权ai,他的问题就是这棵树中有多少个不同的连通块满足连通块的最大值与最小值之差=k,两个连通块不同当且仅当至少存在一个节点在一个连通块中出现而另一个连通块中没有出现。
痴迷于AK的你马上接下这道题目,在里口福狂妄的笑声中,你切掉这道题的决心更加坚定了,现在就差你的代码了。

题解:

我们把密道按权值从小到大排序

对于一条密道(u,v,w),如果u到v的路径上的边中存在边之前还没有被覆盖过,那么说明这条边的答案就是w

把每条边对应到它深度较深的端点上,并查集维护一下每个点向上第一个没有被覆盖的点。从u开始不断向上跳,沿路不断染色,直到跳到超过lca就不再染色。对v也是如此

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;

const int N=1e5+15;
int n,m,tot=1;
int fa[N][20],head[N],dep[N],f[N],ans[N];
ll color[N];
struct E{
    int to,nxt;
}edge[N<<1];
struct EDGE{
    int u,v;
    ll w;
}e[N];
bool operator <(EDGE a,EDGE b){return a.w<b.w;}
inline ll read(){
    char ch=getchar();ll s=0,f=1;
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*f;
}
void link(int u,int v){edge[++tot]=(E){v,head[u]};head[u]=tot;}
void dfs(int x,int pre){
    fa[x][0]=pre;
    for (int i=1;i<20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
    for (int i=head[x];i;i=edge[i].nxt){
        int y=edge[i].to;
        if (y==pre) continue;
        dep[y]=dep[x]+1;
        dfs(y,x);
    }
}
int lca(int x,int y){
    if (dep[x]<dep[y]) swap(x,y);
    for (int i=19;i>=0;i--) if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
    if (x==y) return x;
    for (int i=19;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
int find(int x){
    if (f[x]!=x) f[x]=find(f[x]);
    return f[x];
}
void col(int x,int goal,ll w)
{
    if (dep[x]<dep[goal]+1) return;
    if (f[x]==x) color[x]=w,f[x]=f[fa[x][0]];
    int y=find(x);
    if (dep[y]>=dep[goal]+1) col(y,goal,w);
}
void dfs1(int x,int pre){
    for (int i=head[x];i;i=edge[i].nxt){
        int y=edge[i].to;
        if (y==pre) continue;
        ans[i>>1]=color[y];
        dfs1(y,x);
    }
}
int main()
{
    freopen("worry.in","r",stdin);
    freopen("worry.out","w",stdout);
    n=read();m=read();
    for (int i=1,u,v;i<n;i++){
        u=read();v=read();
        link(u,v);link(v,u);
    }
    dep[1]=1;dfs(1,0);
    for (int i=1;i<=m;i++){
        e[i].u=read();e[i].v=read();
        e[i].w=read();
    }
    for (int i=1;i<=n;i++) f[i]=i;
    sort(e+1,e+1+m);
    for (int i=1;i<=m;i++){
        int u=e[i].u,v=e[i].v;
        ll w=e[i].w;
        int L=lca(u,v);
        col(u,L,w);col(v,L,w);
    }
    dfs1(1,0);
    for (int i=1;i<n;i++) if (!ans[i]) puts("-1");else printf("%d
",ans[i]);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/xxzh/p/9816996.html